use-calendar-timezones.ts2.0 KBView on GitHub import { useCallback, useMemo, useState } from 'react';
const TZ_STORAGE_KEY=[redacted];
/**
* The ordered list of timezone columns shown in the calendar's time gutter. The primary
* (browser) timezone is always LAST — i.e. the column sitting right against the grid, so the
* hours you actually read line up with the events beside them — and cannot be removed.
* Additional zones are prepended to its left and persisted to localStorage so they survive
* reloads.
*/
export function useCalendarTimezones(primaryTimezone: string) {
const [extra, setExtra] = useState<string[]>(() => {
if (typeof window === 'undefined') return [];
try {
const raw = window.localStorage.getItem(TZ_STORAGE_KEY);
const parsed = raw ? JSON.parse(raw) : [];
return Array.isArray(parsed)
? parsed.filter((t): t is string => typeof t === 'string' && t !== primaryTimezone)
: [];
} catch {
return [];
}
});
const persist = useCallback((next: string[]) => {
setExtra(next);
try {
window.localStorage.setItem(TZ_STORAGE_KEY, JSON.stringify(next));
} catch {
// localStorage may be unavailable (private mode); the in-memory list still works.
}
}, []);
const addTimezone = useCallback(
(tz: string) => {
if (tz === primaryTimezone) return;
setExtra((prev) => {
if (prev.includes(tz)) return prev;
const next = [...prev, tz];
try {
window.localStorage.setItem(TZ_STORAGE_KEY, JSON.stringify(next));
} catch {
// ignore
}
return next;
});
},
[primaryTimezone],
);
const removeTimezone = useCallback(
(tz: string) => {
if (tz === primaryTimezone) return;
persist(extra.filter((t) => t !== tz));
},
[extra, persist, primaryTimezone],
);
const timezones = useMemo(
() => [...extra.filter((t) => t !== primaryTimezone), primaryTimezone],
[primaryTimezone, extra],
);
return { timezones, addTimezone, removeTimezone };
}