edtech / apps /admin /src /pages /TrackFormPage.tsx
CognxSafeTrack
feat(i18n): complete admin app internationalization across all pages
d80fec4
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams, useNavigate } from 'react-router-dom';
import { ArrowLeft, Save } from 'lucide-react';
import { useAuth } from '../lib/auth';
import { useTenant } from '../lib/tenant';
import { api } from '../lib/api';
import { logError } from '../lib/logger';
export default function TrackFormPage() {
const { t } = useTranslation();
const { token } = useAuth();
const { selectedOrgId } = useTenant();
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const isNew = id === 'new';
const [form, setForm] = useState({
title: '', description: '', duration: 7, language: 'FR',
isPremium: false, priceAmount: 0
});
const [saving, setSaving] = useState(false);
useEffect(() => {
if (!isNew && token && selectedOrgId) {
api.get(`/v1/admin/tracks/${id}`, token, selectedOrgId)
.then(t => setForm({
title: t.title, description: t.description || '', duration: t.duration,
language: t.language, isPremium: t.isPremium, priceAmount: t.priceAmount || 0
}));
}
}, [id, token, selectedOrgId, isNew]);
const inp = "w-full border border-slate-200 rounded-xl px-4 py-2.5 text-sm outline-none focus:ring-2 focus:ring-slate-300";
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!token || !selectedOrgId) return;
setSaving(true);
const payload = {
...form,
priceAmount: form.priceAmount || undefined
};
try {
if (isNew) {
await api.post('/v1/admin/tracks', payload, token, selectedOrgId);
} else {
await api.put(`/v1/admin/tracks/${id}`, payload, token, selectedOrgId);
}
navigate('/content');
} catch (err) {
logError(err);
} finally {
setSaving(false);
}
};
return (
<div className="p-8 max-w-xl">
<div className="flex items-center gap-3 mb-6">
<button onClick={() => navigate('/content')} className="p-2 hover:bg-slate-100 rounded-lg"><ArrowLeft className="w-4 h-4" /></button>
<h1 className="text-2xl font-bold text-slate-800">{isNew ? t('tracks.new') : t('common.edit')}</h1>
</div>
<form onSubmit={handleSubmit} className="bg-white rounded-2xl border border-slate-100 p-6 space-y-4 shadow-sm">
<div><label className="text-sm font-medium text-slate-700 mb-1 block">{t('tracks.form_title_label')} *</label>
<input required className={inp} value={form.title} onChange={e => setForm(f => ({ ...f, title: e.target.value }))} /></div>
<div><label className="text-sm font-medium text-slate-700 mb-1 block">{t('tracks.form_description')}</label>
<textarea className={inp} rows={3} value={form.description} onChange={e => setForm(f => ({ ...f, description: e.target.value }))} /></div>
<div className="grid grid-cols-2 gap-4">
<div><label className="text-sm font-medium text-slate-700 mb-1 block">{t('tracks.form_duration')}</label>
<input type="number" min={1} required className={inp} value={form.duration} onChange={e => setForm(f => ({ ...f, duration: parseInt(e.target.value) }))} /></div>
<div><label className="text-sm font-medium text-slate-700 mb-1 block">{t('tracks.form_language')}</label>
<select className={inp} value={form.language} onChange={e => setForm(f => ({ ...f, language: e.target.value }))}>
<option value="FR">{t('tracks.form_lang_fr')}</option><option value="WOLOF">{t('tracks.form_lang_wolof')}</option>
</select></div>
</div>
<label className="flex items-center gap-3 p-3 bg-amber-50 rounded-xl cursor-pointer">
<input type="checkbox" checked={form.isPremium} onChange={e => setForm(f => ({ ...f, isPremium: e.target.checked }))} className="w-4 h-4" />
<span className="text-sm font-medium text-amber-800">{t('tracks.form_premium')}</span>
</label>
{form.isPremium && <div>
<label className="text-sm font-medium text-slate-700 mb-1 block">{t('tracks.form_price')}</label>
<input type="number" className={inp} value={form.priceAmount} onChange={e => setForm(f => ({ ...f, priceAmount: parseInt(e.target.value) }))} />
</div>}
<div className="flex gap-3 pt-2">
<button type="button" onClick={() => navigate('/content')} className="flex-1 border border-slate-200 text-slate-600 py-2.5 rounded-xl text-sm hover:bg-slate-50">{t('common.cancel')}</button>
<button
type="submit"
disabled={saving || (isNew && !selectedOrgId)}
className="flex-[2] bg-slate-900 text-white py-2.5 rounded-xl text-sm font-bold flex items-center justify-center gap-2 hover:bg-slate-700 disabled:opacity-50"
>
<Save className="w-4 h-4" />
{saving ? t('common.loading') : (!selectedOrgId && isNew ? t('common.select_org') : t('common.save'))}
</button>
</div>
</form>
</div>
);
}