Files
ToBePlayed-Frontend/src/components/WhatsNewDialog.jsx
T
lobo b811255c16
Build, Test & Push Frontend / quality-check (push) Successful in 25s
Build, Test & Push Frontend / docker (push) Successful in 39s
feat: add What's new feature
Dashboard dialog shows unseen news entries. Users mark them seen with "Got it"
or revisit via the /whats-new page. Admins publish, edit, and delete entries
on /admin/news. Full i18n support and test coverage included.
2026-10-01 10:03:39 +02:00

57 lines
2.0 KiB
React

import {useEffect, useState} from 'react';
import {useTranslation} from 'react-i18next';
import {toast} from 'sonner';
import {Button} from '@/components/ui/button';
import {Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle} from '@/components/ui/dialog';
import NewsEntry from './NewsEntry.jsx';
import {fetchNews, markNewsSeen} from '../utils/news.js';
/**
* The news entries the user has not seen, newest first. Only "Got it" marks them seen: closing the dialog any other
* way shows them again on the next dashboard visit.
*/
export default function WhatsNewDialog() {
const {t} = useTranslation();
const [unseen, setUnseen] = useState([]);
const [open, setOpen] = useState(false);
useEffect(() => {
// A failed load shows nothing, not an error.
fetchNews()
.then((response) => (response.ok ? response.json() : null))
.then((data) => {
const entries = (data?.results ?? []).filter((entry) => !entry.seen);
setUnseen(entries);
setOpen(entries.length > 0);
})
.catch(() => undefined);
}, []);
const gotIt = async () => {
setOpen(false);
try {
const response = await markNewsSeen();
if (!response.ok) toast.error(t('NEWS.SAVE_FAILED'));
} catch {
toast.error(t('INFO.ERROR.NETWORK_FAILURE'));
}
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="max-h-[90vh] overflow-y-auto" aria-describedby={undefined}>
<DialogHeader>
<DialogTitle>{t('NEWS.TITLE')}</DialogTitle>
</DialogHeader>
<div className="space-y-4">
{unseen.map((entry) => <NewsEntry key={entry.id} entry={entry}/>)}
</div>
<DialogFooter>
<Button onClick={gotIt}>{t('NEWS.GOT_IT')}</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}