|
| 1 | +import { settingsStore } from "@/utils/store"; |
| 2 | +import { Button, Group, SegmentedControl, Stack } from "@mantine/core"; |
| 3 | +import { useEffect, useState } from "react"; |
| 4 | +import TimezonesBoard from "./components/TimezonesBoard"; |
| 5 | +import { TimeFormat, TIMEZONE_PREFERENCES_KEY, TimezonePreferencesV1, TimezoneRow } from "./types"; |
| 6 | + |
| 7 | +const DEFAULT_PREFS: TimezonePreferencesV1 = { |
| 8 | + version: 1, |
| 9 | + rows: [{ id: crypto.randomUUID(), label: "India", timeZone: "Asia/Kolkata" }], |
| 10 | + timeFormat: "h24", |
| 11 | + lastReferenceIso: undefined, |
| 12 | + sliderZoom: "hours", |
| 13 | +}; |
| 14 | + |
| 15 | +export default function Timezone() { |
| 16 | + const [preferences, setPreferences] = useState<TimezonePreferencesV1>(DEFAULT_PREFS); |
| 17 | + const [reference, setReference] = useState<Date>(() => |
| 18 | + preferences.lastReferenceIso ? new Date(preferences.lastReferenceIso) : new Date() |
| 19 | + ); |
| 20 | + const [live, setLive] = useState<boolean>(true); |
| 21 | + |
| 22 | + // Keep reference ticking in live mode |
| 23 | + useEffect(() => { |
| 24 | + if (!live) return; |
| 25 | + const interval = 30000; |
| 26 | + const id = window.setInterval(() => setReference(new Date()), interval); |
| 27 | + return () => window.clearInterval(id); |
| 28 | + }, [live]); |
| 29 | + useEffect(() => { |
| 30 | + let mounted = true; |
| 31 | + (async () => { |
| 32 | + const saved = await settingsStore.get<TimezonePreferencesV1>(TIMEZONE_PREFERENCES_KEY); |
| 33 | + if (mounted && saved && saved.version === 1) { |
| 34 | + setPreferences(saved); |
| 35 | + setReference(saved.lastReferenceIso ? new Date(saved.lastReferenceIso) : new Date()); |
| 36 | + } |
| 37 | + })(); |
| 38 | + return () => { |
| 39 | + mounted = false; |
| 40 | + }; |
| 41 | + }, []); |
| 42 | + |
| 43 | + useEffect(() => { |
| 44 | + const toSave: TimezonePreferencesV1 = { |
| 45 | + ...preferences, |
| 46 | + lastReferenceIso: reference.toISOString(), |
| 47 | + }; |
| 48 | + settingsStore.update(TIMEZONE_PREFERENCES_KEY, toSave); |
| 49 | + }, [preferences, reference]); |
| 50 | + |
| 51 | + const handleAdd = () => { |
| 52 | + // Add a draft row that will render inline editor |
| 53 | + const draft: TimezoneRow = { |
| 54 | + id: crypto.randomUUID(), |
| 55 | + label: "", |
| 56 | + timeZone: "UTC", |
| 57 | + isDraft: true, |
| 58 | + isNew: true, |
| 59 | + }; |
| 60 | + setPreferences(prev => ({ ...prev, rows: [...prev.rows, draft] })); |
| 61 | + }; |
| 62 | + |
| 63 | + const handleRemove = (id: string) => { |
| 64 | + setPreferences(prev => ({ ...prev, rows: prev.rows.filter(r => r.id !== id) })); |
| 65 | + }; |
| 66 | + |
| 67 | + return ( |
| 68 | + <Stack className="overflow-padding overflow-auto" h="100%" gap="md" pt="xl"> |
| 69 | + <Group justify="space-between" wrap="nowrap"> |
| 70 | + <Group> |
| 71 | + <SegmentedControl |
| 72 | + data={[ |
| 73 | + { value: "h12", label: "12h" }, |
| 74 | + { value: "h24", label: "24h" }, |
| 75 | + ]} |
| 76 | + value={preferences.timeFormat} |
| 77 | + onChange={e => { |
| 78 | + setPreferences(prev => ({ |
| 79 | + ...prev, |
| 80 | + timeFormat: e as TimeFormat, |
| 81 | + })); |
| 82 | + }} |
| 83 | + size="xs" |
| 84 | + /> |
| 85 | + <Button |
| 86 | + size="xs" |
| 87 | + variant="danger" |
| 88 | + disabled={live} |
| 89 | + onClick={() => { |
| 90 | + setLive(true); |
| 91 | + setReference(new Date()); |
| 92 | + }} |
| 93 | + > |
| 94 | + Reset to now |
| 95 | + </Button> |
| 96 | + </Group> |
| 97 | + <Button size="xs" variant="light" onClick={handleAdd}> |
| 98 | + Add timezone |
| 99 | + </Button> |
| 100 | + </Group> |
| 101 | + |
| 102 | + <TimezonesBoard |
| 103 | + rows={preferences.rows} |
| 104 | + reference={reference} |
| 105 | + timeFormat={preferences.timeFormat} |
| 106 | + onRemove={handleRemove} |
| 107 | + onPauseLive={() => setLive(false)} |
| 108 | + onSetReference={setReference} |
| 109 | + isLive={live} |
| 110 | + onRowChange={(row: TimezoneRow) => |
| 111 | + setPreferences(prev => ({ |
| 112 | + ...prev, |
| 113 | + rows: prev.rows.map(r => (r.id === row.id ? row : r)), |
| 114 | + })) |
| 115 | + } |
| 116 | + /> |
| 117 | + </Stack> |
| 118 | + ); |
| 119 | +} |
0 commit comments