| 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> |
| ); |
| } |
|
|