'use client' import { useState } from 'react' import { useTranslations } from 'next-intl' import { useMissionControl } from '@/store' import { Button } from '@/components/ui/button' type UpdateState = 'idle' | 'updating' | 'restarting' | 'error' export function UpdateBanner() { const { updateAvailable, updateDismissedVersion, dismissUpdate } = useMissionControl() const t = useTranslations('updateBanner') const tc = useTranslations('common') const [state, setState] = useState('idle') const [errorMsg, setErrorMsg] = useState(null) if (!updateAvailable) return null if (updateDismissedVersion === updateAvailable.latestVersion) return null async function handleUpdate() { setState('updating') setErrorMsg(null) try { const res = await fetch('/api/releases/update', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ targetVersion: updateAvailable!.latestVersion }), }) const data = await res.json() if (!res.ok) { setState('error') setErrorMsg(data.error || t('updateFailed')) return } if (data.restartRequired) { setState('restarting') // Poll until the server comes back up, then reload const poll = setInterval(async () => { try { const check = await fetch('/api/releases/check', { cache: 'no-store' }) if (check.ok) { clearInterval(poll) window.location.reload() } } catch { // Server still restarting } }, 2000) // Stop polling after 2 minutes setTimeout(() => { clearInterval(poll) setState('idle') window.location.reload() }, 120_000) } else { window.location.reload() } } catch { setState('error') setErrorMsg(t('networkError')) } } const isbusy = state === 'updating' || state === 'restarting' return (

{state === 'updating' && ( {t('updating')} )} {state === 'restarting' && ( {t('restartingServer')} )} {state === 'error' && ( {errorMsg} )} {state === 'idle' && ( <> {t('updateAvailable', { version: updateAvailable.latestVersion })} {t('newerVersionAvailable')} )}

{!isbusy && ( <> {tc('viewRelease')} )} {isbusy && ( )}
) }