- Move sprint switcher into sprint header, centered between title and actions - Extract BacklogFilterPopover as shared component used by sprint and product backlog - Add sort options (code/priority/status) with single-pill asc/desc toggle - Default sprint backlog status filter to OPEN, remove "alleen niet klaar" button - Persist collapsed state and filter popover open in localStorage - Fix hydration flicker: defer localStorage read to useEffect with prefsLoaded gate for writes - Increase sprint switcher text size for readability Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
22 lines
903 B
TypeScript
22 lines
903 B
TypeScript
/**
|
|
* SSR-safe synchronous read of a localStorage value with a typed parser.
|
|
*
|
|
* Use inside `useState(() => readLocalStoragePref(...))` so the first render
|
|
* already has the persisted value — no useEffect-driven re-render flicker.
|
|
*
|
|
* On the server `window` is undefined → returns `fallback`. On the client the
|
|
* raw value is parsed; if the parser returns `null` the fallback is used.
|
|
* Hydration mismatches between server-rendered HTML (default) and the
|
|
* client-rendered tree (persisted) are accepted: React adapts the DOM in the
|
|
* same hydration pass without a visible flicker for matching values.
|
|
*/
|
|
export function readLocalStoragePref<T>(
|
|
key: string,
|
|
parse: (raw: string) => T | null,
|
|
fallback: T,
|
|
): T {
|
|
if (typeof window === 'undefined') return fallback
|
|
const raw = window.localStorage.getItem(key)
|
|
if (raw === null) return fallback
|
|
return parse(raw) ?? fallback
|
|
}
|