import { defineStore } from 'pinia'; import { computed, ref } from 'vue'; import { playersReplicant } from '../../../browser_shared/replicants'; import type { Schemas } from '../../../types'; import { readStorageSnapshot, syncStateWithReplicant } from './store-sync'; type PlayersMap = Schemas.Players; type Player = PlayersMap[string]; const STORAGE_KEY = 'scoreko-dev.players'; const normalizePlayer = (input: unknown): Player => { const candidate = typeof input === 'object' && input !== null ? (input as Record) : {}; return { gamertag: typeof candidate.gamertag === 'string' ? candidate.gamertag : '', name: typeof candidate.name === 'string' ? candidate.name : '', team: typeof candidate.team === 'string' ? candidate.team : '', country: typeof candidate.country === 'string' ? candidate.country : '', twitter: typeof candidate.twitter === 'string' ? candidate.twitter : '', }; }; const normalizePlayers = (input: unknown): PlayersMap => { if (typeof input !== 'object' || input === null) { return {}; } const result: PlayersMap = {}; Object.entries(input as Record).forEach(([id, value]) => { if (!id) { return; } result[id] = normalizePlayer(value); }); return result; }; export const usePlayersStore = defineStore('players', () => { const players = ref({}); const replicant = playersReplicant; const storageSnapshot = readStorageSnapshot(STORAGE_KEY, normalizePlayers); if (storageSnapshot) { players.value = storageSnapshot; } syncStateWithReplicant(players, replicant, normalizePlayers, STORAGE_KEY); const setPlayers = (value: PlayersMap) => { players.value = normalizePlayers(value); }; const upsertPlayer = (id: string, player: Player) => { players.value = { ...players.value, [id]: normalizePlayer(player), }; }; const removePlayer = (id: string) => { const next = { ...players.value }; delete next[id]; players.value = next; }; const rows = computed(() => Object.entries(players.value).map(([id, player]) => ({ id, ...player, }))); return { players, rows, setPlayers, upsertPlayer, removePlayer, }; });