fix(time-tracking): inherit lang from water-log and stop PIN flash
Deploy to route.crispygoat.com / deploy (push) Successful in 4m18s

Two UX bugs in the worker Time Tracking mobile flow:

1) Spanish parity between Water Log and Time Tracking. The Water Log
   mobile app (/water) uses the wl_lang cookie for its language; the
   Time Tracking field client used its own time_tracking_lang cookie.
   A worker who set Spanish on /water then tapped the Time tab saw
   English. getLangCookie() now falls back to wl_lang when
   time_tracking_lang is unset, so the Time tab inherits the worker's
   Water Log preference. Standalone /tuxedo/time-clock is unaffected
   (no wl_lang cookie there).

2) PIN screen flash on tab change. initialState started at screen
   'pin', so the init effect that resolves the session cookie + open
   clock-in caused a one-tick flash of the PIN screen even when the
   worker was already authenticated. initialState now starts at
   'loading' (a spinner) and the init effect dispatches the correct
   screen (hub / working / pin) once the session check resolves.

Public contract unchanged: exported types, function signatures, and
the cookie name on writes are all preserved. The change is additive
on read (extra cookie fallback) and a one-key swap on initial state.

Verified locally: tsc clean, lint unchanged (354 problems = baseline),
vitest 226 pass / 29 fail (same pre-existing auth failures, none
related to this change).
This commit is contained in:
Nora
2026-07-06 10:05:55 -06:00
parent c7c83890e4
commit 6f1aa37a26
@@ -392,8 +392,15 @@ const TRANS_ES: Translations = {
function getLangCookie(): string {
if (typeof document === "undefined") return "en";
const match = document.cookie.match(/time_tracking_lang=(\w+)/);
return match ? match[1] : "en";
// `time_tracking_lang` is the explicit override. Fall back to
// `wl_lang` so workers who switched to Spanish on the Water Log
// mobile app inherit the same language when they tap the Time tab
// — without this, the Time tab resets to English every time.
const tt = document.cookie.match(/time_tracking_lang=(\w+)/);
if (tt) return tt[1];
const wl = document.cookie.match(/wl_lang=(\w+)/);
if (wl) return wl[1];
return "en";
}
function setLangCookie(lang: string) {
@@ -410,8 +417,8 @@ function langToBcp(): "en-US" | "es-ES" {
// Cheap global so `formatTime` doesn't have to thread `lang` around.
// Resolved at call time from the lang cookie that's always set.
if (typeof document === "undefined") return "en-US";
const m = document.cookie.match(/time_tracking_lang=(\w+)/);
return m?.[1] === "es" ? "es-ES" : "en-US";
const m = getLangCookie();
return m === "es" ? "es-ES" : "en-US";
}
function formatHours(minutes: number): string {
@@ -538,7 +545,12 @@ function emptyManualDraft(): State["manualEntryDraft"] {
const initialState: State = {
lang: (getLangCookie() as "en" | "es") ?? "en",
screen: "pin",
// Start in `"loading"` so the init effect can resolve the session
// cookie + open clock-in before the UI renders. Previously this
// was `"pin"`, which caused a ~one-tick flash of the PIN screen on
// every tab switch — workers with a valid session saw the PIN UI
// for a moment before it was swapped out for Hub/Working.
screen: "loading",
tasks: [],
openEntry: null,
payPeriod: null,