Files
galaxy-game/ui/frontend/src/lib/account-store.svelte.ts
T
Ilia Denisov a679d9cdcb
Tests · UI / test (push) Has been cancelled
Tests · Go / test (push) Successful in 2m30s
Tests · UI / test (pull_request) Successful in 2m49s
fix(ui): F8-04 profile polish — IANA timezone picker, save-stay, shared identity cache
PR-feedback round on #60:

- Time-zone field is now a continent-grouped <select> populated from
  `Intl.supportedValuesOf("timeZone")`, with the browser-detected
  zone pre-selected when no value is stored. A stored zone the
  runtime no longer advertises is preserved as an "Other" entry.
- Saving the profile no longer kicks the user back to the lobby:
  the form stays put and shows a transient `saved` notice, cleared
  on the next edit. Only `cancel` returns to the lobby.
- New `lib/account-store.svelte.ts` caches `user.account.get` for
  the session; lobby + profile share it through `account.ensure()`,
  so navigating Overview ⇄ Profile no longer flashes the
  "loading account…" placeholder or fires a second gateway call.
  Profile save writes through to the store so the shell identity
  strip picks up the new display name without refetching. Cleared
  on logout to prevent identity bleed between accounts.
- e2e: existing 4 cases adjusted for save-stay; added two new ones
  for the timezone dropdown and identity-strip stability across
  navigation.
- Docs: `ui/docs/lobby.md` updated to describe the shared cache,
  the new timezone picker shape, and the save-stay behaviour.
2026-05-26 22:38:14 +02:00

77 lines
2.6 KiB
TypeScript

// `AccountStore` is the session-wide cache for the caller's
// `user.account.get` aggregate. The lobby shell and every post-login
// screen read the identity (display name, immutable user_name, time
// zone, …) from the same rune, so navigating between Overview and
// Profile does not refetch and does not flash the
// `lobby.account_loading` placeholder.
//
// `ensure(client)` fetches once on first call, dedupes concurrent
// callers onto a single in-flight promise, and resolves immediately
// from the cache thereafter. `set(account)` is the write-through
// path used by Profile after `user.profile.update` /
// `user.settings.update` succeeds — both the shell and the screen
// pick up the change without an extra round-trip. `clear()` resets
// the cache on logout so a different user signing in on the same
// browser does not briefly see the previous identity.
//
// The store is intentionally narrow: it caches one struct, never
// retries on failure (the caller decides), and exposes no error
// state of its own. Callers that need a tighter error surface (the
// Profile form) catch the rejection from `ensure(client)` directly.
import type { GalaxyClient } from "../api/galaxy-client";
import { getMyAccount, type Account } from "../api/account";
class AccountStore {
current: Account | null = $state(null);
#inFlight: Promise<Account> | null = null;
/**
* ensure returns the cached `Account` when present, otherwise issues
* `user.account.get` through the supplied client and caches the
* result. Concurrent callers during the first fetch share the same
* in-flight promise so the gateway only sees one request per
* session.
*/
ensure(client: GalaxyClient): Promise<Account> {
if (this.current !== null) {
return Promise.resolve(this.current);
}
if (this.#inFlight !== null) {
return this.#inFlight;
}
const pending = getMyAccount(client)
.then((account) => {
this.current = account;
return account;
})
.finally(() => {
this.#inFlight = null;
});
this.#inFlight = pending;
return pending;
}
/**
* set replaces the cached `Account` with the supplied value. Used
* by the Profile screen after a successful save so both the form
* and the shell identity strip pick up the new fields without a
* second round-trip.
*/
set(next: Account): void {
this.current = next;
}
/**
* clear resets the cache. Called on logout so a different user
* signing in on the same browser does not briefly see the
* previous identity through the rune.
*/
clear(): void {
this.current = null;
this.#inFlight = null;
}
}
export const account = new AccountStore();