/** * 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)}

}
{notice &&
{notice}
} {sync.error &&
{sync.error}
} {/* Status-Filter */} setStatus('')} > {loading &&

{de.common.loading}

} {requests.error && (
{requests.error}
)} {!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 &&
) }