import {useCallback, useEffect, useState} from 'react'; import {useTranslation} from 'react-i18next'; import {Loader2, Pencil, Send, Trash2} from 'lucide-react'; import {toast} from 'sonner'; import {Button} from '@/components/ui/button'; import {Card, CardContent, CardHeader, CardTitle} from '@/components/ui/card'; import {Input} from '@/components/ui/input'; import {Label} from '@/components/ui/label'; import {Textarea} from '@/components/ui/textarea'; import NewsEntry from '../components/NewsEntry.jsx'; import PageContainer from '../components/PageContainer.jsx'; import {MAX_NEWS_TEXT_LENGTH, MAX_NEWS_TITLE_LENGTH} from '../utils/limits.js'; import {createNews, deleteNews, fetchAdminNews, updateNews} from '../utils/news.js'; const emptyForm = () => ({titleEn: '', titleDe: '', textEn: '', textDe: ''}); /** * PLATFORM_ADMIN only: publish, preview, edit and delete the "What's new" entries. Auth checks the role. */ export default function AdminNewsPage() { const {t} = useTranslation(); const [entries, setEntries] = useState([]); const [status, setStatus] = useState('loading'); const [form, setForm] = useState(emptyForm); const [editing, setEditing] = useState(null); const [busy, setBusy] = useState(false); const load = useCallback(async () => { try { const response = await fetchAdminNews(); if (response.status === 401) return; if (response.status === 403) { setStatus('forbidden'); return; } if (!response.ok) { setStatus('error'); return; } setEntries((await response.json()).results); setStatus('ready'); } catch (err) { console.error('Admin news error:', err); setStatus('error'); } }, []); useEffect(() => { load(); }, [load]); const run = async (request, doneKey, onOk) => { setBusy(true); try { const response = await request(); if (response.status === 401) return; if (response.ok) { toast.success(t(doneKey)); onOk?.(); await load(); } else { toast.error(t('ADMIN_NEWS.ERROR')); } } catch (err) { console.error('Admin news action error:', err); toast.error(t('INFO.ERROR.NETWORK_FAILURE')); } finally { setBusy(false); } }; const trimmed = () => ({ titleEn: form.titleEn.trim(), titleDe: form.titleDe.trim(), textEn: form.textEn.trim(), textDe: form.textDe.trim(), }); const reset = () => { setForm(emptyForm()); setEditing(null); }; const submit = (event) => { event.preventDefault(); const news = trimmed(); if (editing == null) run(() => createNews(news), 'ADMIN_NEWS.CREATED', reset); else run(() => updateNews(editing, news), 'ADMIN_NEWS.UPDATED', reset); }; const edit = (entry) => { setEditing(entry.id); setForm({titleEn: entry.titleEn, titleDe: entry.titleDe ?? '', textEn: entry.textEn, textDe: entry.textDe ?? ''}); }; const remove = (entry) => { if (!window.confirm(t('ADMIN_NEWS.CONFIRM_DELETE'))) return; run(() => deleteNews(entry.id), 'ADMIN_NEWS.DELETED', () => editing === entry.id && reset()); }; const change = (field) => (event) => setForm({...form, [field]: event.target.value}); if (status === 'forbidden') { return ( {t('ADMIN_NEWS.NO_ACCESS')} ); } return ( {t(editing == null ? 'ADMIN_NEWS.NEW' : 'ADMIN_NEWS.EDIT')} {t('ADMIN_NEWS.TITLE_EN')} {t('ADMIN_NEWS.TEXT_EN')} {t('ADMIN_NEWS.TITLE_DE')} {t('ADMIN_NEWS.TEXT_DE')} {t('ADMIN_NEWS.TEXT_HELP')} {form.titleEn.trim() && form.textEn.trim() && ( {t('ADMIN_NEWS.PREVIEW')} )} {busy ? : } {t(editing == null ? 'ADMIN_NEWS.CREATE' : 'ADMIN_NEWS.SAVE')} {editing != null && ( {t('ADMIN_NEWS.CANCEL')} )} {t('ADMIN_NEWS.LIST')} {status === 'loading' && } {status === 'error' && {t('ADMIN_NEWS.LOAD_ERROR')}} {status === 'ready' && entries.length === 0 && {t('ADMIN_NEWS.EMPTY')}} {status === 'ready' && entries.length > 0 && ( {entries.map((entry) => ( edit(entry)}> {t('ADMIN_NEWS.EDIT_ACTION')} remove(entry)}> {t('ADMIN_NEWS.DELETE')} ))} )} ); }
{t('ADMIN_NEWS.NO_ACCESS')}
{t('ADMIN_NEWS.TEXT_HELP')}
{t('ADMIN_NEWS.PREVIEW')}
{t('ADMIN_NEWS.LOAD_ERROR')}
{t('ADMIN_NEWS.EMPTY')}