import type { RestoreStatusResponse } from '@dorfteich/shared'; import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { apiGet } from '../lib/api'; const POLL_INTERVAL_MS = 3000; /** * The status page behind maintenance mode (issue #103): while a backup * restore runs, every api call answers 503, and this screen polls the one * exempt endpoint. Once the restore is over and the api answers again, the * page reloads itself — after a successful restore the whole client state * is stale anyway. */ export function MaintenancePage(): React.JSX.Element { const { t } = useTranslation('system'); const [status, setStatus] = useState(null); useEffect(() => { let cancelled = false; const poll = async (): Promise => { let current: RestoreStatusResponse | null = null; try { current = await apiGet('/backup/restore-status'); } catch { current = null; // api restarting — keep waiting } if (cancelled) return; setStatus(current); if (current && current.state !== 'running' && current.state !== 'failed') { // idle or succeeded: check the api serves normally again, then reload. try { await apiGet('/healthz'); if (!cancelled) window.location.reload(); return; } catch { // still restarting } } if (!cancelled) setTimeout(() => void poll(), POLL_INTERVAL_MS); }; void poll(); return () => { cancelled = true; }; }, []); const failedStatus = status !== null && status.state === 'failed' ? status : null; return (

{t('maintenance.title')}

{t('maintenance.body')}

{failedStatus ? ( <>

{t('maintenance.failed', { error: failedStatus.error ?? '' })}

) : (

{t('maintenance.waiting')}

)}
); }