Keep a settings change made before the first read, and wait for it
Two defects on the path that decides what language the app starts in. **A change made before the settings file came back was thrown away.** `queueSettingsPush` returned early while unarmed, dropping the value instead of holding it, so a language picked in the second or so after a page load was never written up: it survived until the next reload and no further. That is a better account of "sometimes it takes several clicks" than the remount race fixed in #160 — the click that stuck was one made after the read had finished. Keeping it is safe because hydrate already refuses to overwrite a key that is still queued. Proof it was real: before this, no `ihasmail` folder was ever created in the account's files, because the seed write never fired. After it, the folder appears. **Without a cached settings object the tree painted too early.** The cache is not read on an untrusted device, and it is cleared by the sign-out that every deploy causes, so in both cases the first frame is the defaults — and the defaults are English. Anything computed in that window is computed in the wrong language. The interface recovers, since it is rebuilt when the catalogue lands, but a string emitted once does not: this is why the stale-folder toast came out in English on an otherwise German screen. So without a cache the authenticated tree now waits for the account's settings and their catalogue, which costs nothing — there was nothing worth painting yet. With a cache it does not wait, and the first frame is as quick as it was. Neither fix makes the toast German yet: the account settings file is neither written nor read successfully in the mock, and both failures are swallowed. That is a third problem, and this commit does not touch it.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { create } from "zustand";
|
||||
import { loadJson, saveJson } from "@/lib/storage";
|
||||
import { hasCachedJson, loadJson, saveJson } from "@/lib/storage";
|
||||
import { pendingSettingsKeys, queueSettingsPush } from "@/lib/settingsSync";
|
||||
import { setDateTimePrefs, setUiLanguageForFormatting, type DateFormat, type TimeFormat } from "@/lib/datetime";
|
||||
import type { SwipeAction } from "@/lib/swipe";
|
||||
@@ -311,6 +311,17 @@ interface SettingsState {
|
||||
}
|
||||
|
||||
const initialSettings = loadJson<Settings>("settings", DEFAULT_SETTINGS);
|
||||
|
||||
/**
|
||||
* Whether the first frame is this account's settings or merely the defaults.
|
||||
*
|
||||
* False after every deploy, because deploys sign everyone out and sign-out
|
||||
* clears the cache -- and false on any untrusted device, where the cache is
|
||||
* never read. In that state `uiLanguage` starts as English and only becomes
|
||||
* the account's choice once the settings file lands, which is why the
|
||||
* authenticated tree waits for it.
|
||||
*/
|
||||
export const PAINTED_FROM_CACHE = hasCachedJson("settings");
|
||||
applyDateTimePrefs(initialSettings);
|
||||
|
||||
export const useSettings = create<SettingsState>((set, get) => ({
|
||||
|
||||
Reference in New Issue
Block a user