refactor: simplify widget reload persistence
This commit is contained in:
8 files changed
+79
-241
No files matched your search
@@ -10,7 +10,7 @@ import { AdvancedClockView } from "./advanced-view";
|
||||
import { clockTimeFormatShowsSeconds, resolveClockTimeFormat } from "./format";
|
||||
import { useCurrentTime } from "./use-current-time";
|
||||
import { ClockWeatherSummary } from "./weather-summary";
|
||||
import { getResolvedLocalTimeZone, isTimeZoneSupported } from "./world-clock";
|
||||
import { isTimeZoneSupported } from "./world-clock";
|
||||
|
||||
dayjs.extend(advancedFormat);
|
||||
|
||||
@@ -18,10 +18,8 @@ export default function ClockWidget({ options, width, height, displayMode }: Wid
|
||||
const isAdvanced = displayMode === "advanced";
|
||||
const showSeconds = clockTimeFormatShowsSeconds(options.customTimeFormat);
|
||||
const time = useCurrentTime({ showSeconds });
|
||||
const initialLocalTimeZone = useWidgetLocalTimeZone();
|
||||
const requestedTimeZone = options.useCustomTimezone
|
||||
? options.timezone
|
||||
: (initialLocalTimeZone ?? getResolvedLocalTimeZone());
|
||||
const localTimeZone = useWidgetLocalTimeZone();
|
||||
const requestedTimeZone = options.useCustomTimezone ? options.timezone : localTimeZone;
|
||||
const primaryTimeZoneInvalid = !isTimeZoneSupported(requestedTimeZone);
|
||||
const primaryTimeZone = primaryTimeZoneInvalid ? "UTC" : requestedTimeZone;
|
||||
const zonedTime = time === null ? null : dayjs(time).tz(primaryTimeZone);
|
||||
|
||||
@@ -24,9 +24,11 @@ describe("WidgetTimeProvider", () => {
|
||||
vi.useFakeTimers();
|
||||
const serverTimestamp = new Date("2026-08-22T12:34:00.000Z").getTime();
|
||||
const clientTimestamp = serverTimestamp + 60_000;
|
||||
const browserTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
||||
const serverTimeZone = browserTimeZone === "UTC" ? "Europe/Paris" : "UTC";
|
||||
vi.setSystemTime(serverTimestamp);
|
||||
const content = (
|
||||
<WidgetTimeProvider initialTimestamp={serverTimestamp} initialTimeZone="UTC">
|
||||
<WidgetTimeProvider initialTimestamp={serverTimestamp} initialTimeZone={serverTimeZone}>
|
||||
<TimeProbe />
|
||||
</WidgetTimeProvider>
|
||||
);
|
||||
@@ -34,15 +36,12 @@ describe("WidgetTimeProvider", () => {
|
||||
const host = document.createElement("div");
|
||||
host.innerHTML = html;
|
||||
const consoleError = vi.spyOn(console, "error").mockImplementation(() => undefined);
|
||||
vi.spyOn(Intl.DateTimeFormat.prototype, "resolvedOptions").mockReturnValue({
|
||||
timeZone: "Europe/Paris",
|
||||
} as Intl.ResolvedDateTimeFormatOptions);
|
||||
vi.setSystemTime(clientTimestamp);
|
||||
|
||||
expect(host.textContent).toBe("2026-08-22T12:34:00.000Z|UTC");
|
||||
expect(host.textContent).toBe(`2026-08-22T12:34:00.000Z|${serverTimeZone}`);
|
||||
const root = hydrateRoot(host, content);
|
||||
await act(async () => undefined);
|
||||
expect(host.textContent).toBe("2026-08-22T12:35:00.000Z|Europe/Paris");
|
||||
expect(host.textContent).toBe(`2026-08-22T12:35:00.000Z|${browserTimeZone}`);
|
||||
expect(consoleError).not.toHaveBeenCalled();
|
||||
|
||||
await act(async () => root.unmount());
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import type { PropsWithChildren } from "react";
|
||||
import { createContext, useContext, useEffect, useMemo, useState } from "react";
|
||||
import { createContext, useContext, useSyncExternalStore } from "react";
|
||||
|
||||
interface WidgetTimeContextValue {
|
||||
initialTimestamp: number | null;
|
||||
localTimeZone: string | null;
|
||||
}
|
||||
|
||||
const WidgetTimeContext = createContext<WidgetTimeContextValue>({ initialTimestamp: null, localTimeZone: null });
|
||||
const WidgetTimestampContext = createContext<number | null>(null);
|
||||
const WidgetTimeZoneContext = createContext("UTC");
|
||||
|
||||
interface WidgetTimeProviderProps {
|
||||
initialTimestamp: number;
|
||||
@@ -19,19 +15,21 @@ export const WidgetTimeProvider = ({
|
||||
children,
|
||||
initialTimestamp,
|
||||
initialTimeZone,
|
||||
}: PropsWithChildren<WidgetTimeProviderProps>) => {
|
||||
const [localTimeZone, setLocalTimeZone] = useState(() => getSupportedTimeZone(initialTimeZone));
|
||||
}: PropsWithChildren<WidgetTimeProviderProps>) => (
|
||||
<WidgetTimestampContext.Provider value={initialTimestamp}>
|
||||
<WidgetTimeZoneContext.Provider value={getSupportedTimeZone(initialTimeZone)}>
|
||||
{children}
|
||||
</WidgetTimeZoneContext.Provider>
|
||||
</WidgetTimestampContext.Provider>
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setLocalTimeZone(getResolvedLocalTimeZone());
|
||||
}, []);
|
||||
|
||||
const value = useMemo(() => ({ initialTimestamp, localTimeZone }), [initialTimestamp, localTimeZone]);
|
||||
return <WidgetTimeContext.Provider value={value}>{children}</WidgetTimeContext.Provider>;
|
||||
export const useWidgetInitialTimestamp = () => useContext(WidgetTimestampContext);
|
||||
export const useWidgetLocalTimeZone = () => {
|
||||
const initialTimeZone = useContext(WidgetTimeZoneContext);
|
||||
return useSyncExternalStore(subscribeToTimeZone, getResolvedLocalTimeZone, () => initialTimeZone);
|
||||
};
|
||||
|
||||
export const useWidgetInitialTimestamp = () => useContext(WidgetTimeContext).initialTimestamp;
|
||||
export const useWidgetLocalTimeZone = () => useContext(WidgetTimeContext).localTimeZone;
|
||||
const subscribeToTimeZone = () => () => undefined;
|
||||
|
||||
const getResolvedLocalTimeZone = () => getSupportedTimeZone(Intl.DateTimeFormat().resolvedOptions().timeZone);
|
||||
|
||||
|
||||
Reference in new issue
Block a user