watch-party/frontend/src/components/TimeSyncNotice.tsx
2025-11-11 18:06:45 +09:00

62 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useEffect, useState } from "react";
import { useTimeSkew } from "../hooks/useTimeSkew";
function formatMs(ms: number) {
const sign = ms > 0 ? "+" : "";
return `${sign}${ms}ms`;
}
export default function TimeSyncNotice({
thresholdMs = 500,
endpoint,
intervalMs,
lang = "ja",
}: {
thresholdMs?: number;
endpoint?: string;
intervalMs?: number;
lang?: "ja" | "en";
}) {
// removed `error`
const { skewMs, rttMs, recheck } = useTimeSkew({ endpoint, intervalMs });
const [dismissed, setDismissed] = useState<boolean>(() => {
try { return sessionStorage.getItem("timesync.dismissed") === "1"; } catch { return false; }
});
useEffect(() => {
if (skewMs != null && Math.abs(skewMs) <= thresholdMs && dismissed) {
setDismissed(false);
try { sessionStorage.removeItem("timesync.dismissed"); } catch { }
}
}, [skewMs, thresholdMs, dismissed]);
if (dismissed || skewMs == null || Math.abs(skewMs) <= thresholdMs) return null;
const ahead = skewMs > 0;
const msgJa = ahead
? `端末の時計が正確な時刻より ${formatMs(skewMs)} 進んでいます(往復遅延 ${rttMs ?? "-"}ms`
: `端末の時計が正確な時刻より ${formatMs(-skewMs)} 遅れています(往復遅延 ${rttMs ?? "-"}ms`;
const msgEn = ahead
? `Your device clock is ${formatMs(skewMs)} ahead of the correct time (RTT ${rttMs ?? "-"}ms).`
: `Your device clock is ${formatMs(-skewMs)} behind the correct time (RTT ${rttMs ?? "-"}ms).`;
const onClose = () => {
setDismissed(true);
try { sessionStorage.setItem("timesync.dismissed", "1"); } catch { }
};
return (
<div className="timesync-banner" role="status" aria-live="polite">
<div className="timesync-msg">{lang === "ja" ? msgJa : msgEn}</div>
<div className="timesync-actions">
<button className="timesync-btn" onClick={() => recheck?.()}>
{lang === "ja" ? "再測定" : "Re-check"}
</button>
<button className="timesync-close" onClick={onClose} aria-label={lang === "ja" ? "閉じる" : "Close"}>
×
</button>
</div>
</div>
);
}