/** * INBOX-1: Anfragen-Posteingang — Liste mit Status-Filter (Gridify) und * manuellem Gmail-Abruf („Anfragen abrufen“, POST /api/requests/sync). * Solange Gmail unkonfiguriert ist, antwortet der Sync mit MailNotConfigured * → freundlicher deutscher Hinweis statt Fehler. */ import { useState } from 'react' import { Link } from 'react-router-dom' import { de } from '../strings/de' import { REQUEST_STATUSES, listRequests, syncRequests, type RequestStatus, } from '../api/requests' import { useMutation } from '../hooks/useApi' import { useInfiniteList, useInfiniteSentinel } from '../hooks/useInfiniteList' import { formatDateTime } from '../format/labels' import { FilterPanel } from '../components/FilterPanel' import './anfragen.css' const PAGE_SIZE = 20 export function StatusBadge({ status }: { status: RequestStatus }) { return ( {de.pages.anfragen.statusLabels[status]} ) } export default function AnfragenPage() { const t = de.pages.anfragen const [status, setStatus] = useState('') const [notice, setNotice] = useState(null) const requests = useInfiniteList( (page) => listRequests({ page, pageSize: PAGE_SIZE, orderBy: 'receivedAt desc,id', filter: status === '' ? undefined : `status==${status}`, }), `${status}`, 'anfragen', ) const sentinelRef = useInfiniteSentinel(requests) const { items, total, loading } = requests const sync = useMutation(() => syncRequests()) async function onSync() { setNotice(null) const result = await sync.run() if (!result.ok) return // sync.error treibt den Alert if (result.value.error === 'MailNotConfigured') setNotice(t.mailNotConfigured) else if (result.value.error === 'MailAuthFailed') setNotice(t.mailAuthFailed) else { setNotice(t.syncImported(result.value.imported)) if (result.value.imported > 0) requests.reload() } } return ( {t.title} {!loading && {t.countText(total)}} {sync.pending ? t.syncing : t.sync} {notice && {notice}} {sync.error && {sync.error}} {/* Status-Filter */} setStatus('')} > {t.detail.statusLabel} setStatus(e.target.value as RequestStatus | '')} > {t.filterAll} {REQUEST_STATUSES.map((s) => ( {t.statusLabels[s]} ))} {loading && {de.common.loading}} {requests.error && ( {requests.error} {de.common.retry} )} {!loading && items.length === 0 && ( {status === '' ? t.empty : t.emptyFiltered} )} {items.length > 0 && ( {items.map((r) => ( {r.fromName ?? r.fromAddress} {r.subject ?? de.pages.anfragen.detail.noSubject} {formatDateTime(r.receivedAt)} ))} )} {/* Infinite-scroll sentinel + "loading more" indicator. */} {requests.hasMore && } {requests.loadingMore && ( {de.common.loading} )} ) }
{t.countText(total)}
{de.common.loading}
{status === '' ? t.empty : t.emptyFiltered}