import { useEffect, useState } from 'react'; import { api } from '../api/client'; import type { MetadataHeroSettingsResponse } from '../api/types'; import { Banner, Button, Card, Loading, PageHead, Segments, Toggle } from '../components/ui'; import { useAction, useQuery } from '../lib/hooks'; import { useToast } from '../lib/toast'; const DEFAULT_ORDER = ['title', 'ratings', 'facts', 'summary']; export function MetadataHeroPage() { const query = useQuery('/admin/api/metadata-hero'); const { busy, run } = useAction(); const { wrap } = useToast(); const [order, setOrder] = useState(null); const [timeRemainingColour, setTimeRemainingColour] = useState<'green' | 'white' | null>(null); useEffect(() => { if (order === null && query.data) setOrder(query.data.settings.contentOrder); if (timeRemainingColour === null && query.data) { setTimeRemainingColour(query.data.settings.timeRemainingColour ?? 'green'); } }, [order, query.data, timeRemainingColour]); const selected = order ?? DEFAULT_ORDER; const selectedTimeRemainingColour = timeRemainingColour ?? 'green'; const options = query.data?.options ?? []; const displayOptions = [ ...selected, ...options.map((option) => option.value).filter((value) => !selected.includes(value)), ]; const move = (value: string, offset: number) => { const from = selected.indexOf(value); const to = from + offset; if (from < 0 || to < 0 || to >= selected.length) return; const next = [...selected]; const moved = next[from]; next[from] = next[to]!; next[to] = moved!; setOrder(next); }; const save = () => run('save', async () => { const response = await wrap( () => api.post('/admin/api/metadata-hero', { contentOrder: selected, timeRemainingColour: selectedTimeRemainingColour, }), 'Metadata hero saved for every television.', ); if (response) { query.set(response); setOrder(response.settings.contentOrder); setTimeRemainingColour(response.settings.timeRemainingColour); } }); return ( <> {query.loading ? : (
} >
{displayOptions.map((value) => { const option = options.find((entry) => entry.value === value); if (!option) return null; const index = selected.indexOf(value); const enabled = index >= 0; return (
{enabled ? index + 1 : '—'} setOrder(on ? [...selected, value] : selected.filter((entry) => entry !== value))} />
); })}
Time-remaining text colour

Choose the caption colour used beside the resume progress bar.

{selected.map((section) => { if (section === 'title') return
THE SOUTHERN LIGHT
; if (section === 'ratings') return
IMDb 8.2TMDb 81%
; if (section === 'facts') return
2026   •   1h 54m   •   M   •   Drama, Mystery 4K5.1
; if (section === 'recommendation_reason') return
Because you watched Harbour Lights
; if (section === 'time_remaining') return
47 minutes remaining
; if (section === 'summary') return

A quiet coastal town follows an unexpected signal across the winter sky.

; return null; })}
)} ); }