feat(ui): add profile client store with LocalStorage persistence

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-17 15:28:21 +02:00
parent 1adc0ee021
commit e90545a637

View File

@@ -0,0 +1,62 @@
import type { Profile } from '$lib/types';
const STORAGE_KEY = 'kochwas.activeProfileId';
function loadActiveId(): number | null {
if (typeof localStorage === 'undefined') return null;
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
const n = Number(raw);
return Number.isInteger(n) && n > 0 ? n : null;
}
function saveActiveId(id: number | null): void {
if (typeof localStorage === 'undefined') return;
if (id === null) localStorage.removeItem(STORAGE_KEY);
else localStorage.setItem(STORAGE_KEY, String(id));
}
class ProfileStore {
profiles = $state<Profile[]>([]);
activeId = $state<number | null>(null);
loaded = $state(false);
active = $derived(this.profiles.find((p) => p.id === this.activeId) ?? null);
async load(): Promise<void> {
const res = await fetch('/api/profiles');
this.profiles = await res.json();
const stored = loadActiveId();
if (stored && this.profiles.some((p) => p.id === stored)) {
this.activeId = stored;
}
this.loaded = true;
}
select(id: number): void {
this.activeId = id;
saveActiveId(id);
}
clear(): void {
this.activeId = null;
saveActiveId(null);
}
async create(name: string, avatar_emoji: string | null): Promise<Profile> {
const res = await fetch('/api/profiles', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ name, avatar_emoji })
});
if (!res.ok) {
const err = await res.json().catch(() => ({ message: 'unknown error' }));
throw new Error(err.message ?? 'failed to create profile');
}
const p = (await res.json()) as Profile;
this.profiles = [...this.profiles, p].sort((a, b) => a.name.localeCompare(b.name));
return p;
}
}
export const profileStore = new ProfileStore();