File size: 5,627 Bytes
de6a95b 6b2ad5a de6a95b e289c5c 6dd9bad a966957 de6a95b 6b2ad5a e289c5c de6a95b 7b0c22b de6a95b 2ab1980 6dd9bad de6a95b 7b0c22b de6a95b 2ab1980 de6a95b 2ab1980 de6a95b 6dd9bad a966957 6dd9bad de6a95b 6b2ad5a de6a95b d80fec4 de6a95b d80fec4 de6a95b d80fec4 de6a95b d80fec4 de6a95b d80fec4 de6a95b d80fec4 de6a95b 7b0c22b d80fec4 7b0c22b de6a95b 6b2ad5a e289c5c 6b2ad5a de6a95b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 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>
);
}
|