From ad10d3fe73ae7f81c15447b42fe6bd38f2236422 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 30 Nov 2025 20:06:09 -0800 Subject: [PATCH] stores: add partyStore for character/weapon updates --- src/lib/stores/partyStore.svelte.ts | 110 ++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/lib/stores/partyStore.svelte.ts diff --git a/src/lib/stores/partyStore.svelte.ts b/src/lib/stores/partyStore.svelte.ts new file mode 100644 index 00000000..b338e738 --- /dev/null +++ b/src/lib/stores/partyStore.svelte.ts @@ -0,0 +1,110 @@ +import type { Party, GridCharacter, GridWeapon, GridSummon } from '$lib/types/api/party' +import { gridAdapter } from '$lib/api/adapters/grid.adapter' + +/** + * Global party store for reactive access to party data + * Used to bridge party data between the Party component and components rendered outside the party context (like DetailsSidebar) + */ +class PartyStore { + party = $state(null) + + setParty(party: Party | null) { + this.party = party + } + + get shortcode(): string | undefined { + return this.party?.shortcode + } + + getCharacter(id: string | number): GridCharacter | undefined { + return this.party?.characters?.find((c) => String(c.id) === String(id)) + } + + getWeapon(id: string | number): GridWeapon | undefined { + return this.party?.weapons?.find((w) => String(w.id) === String(id)) + } + + getSummon(id: string | number): GridSummon | undefined { + return this.party?.summons?.find((s) => String(s.id) === String(id)) + } + + getItem( + type: 'character' | 'weapon' | 'summon', + id: string | number + ): GridCharacter | GridWeapon | GridSummon | undefined { + switch (type) { + case 'character': + return this.getCharacter(id) + case 'weapon': + return this.getWeapon(id) + case 'summon': + return this.getSummon(id) + } + } + + /** + * Update a character in the party (optimistically updates local state and calls API) + */ + async updateCharacter(id: string, updates: Partial): Promise { + // Optimistically update local state + if (this.party?.characters) { + this.party = { + ...this.party, + characters: this.party.characters.map((c) => + String(c.id) === String(id) ? { ...c, ...updates } : c + ) + } + } + + // Call API + const updated = await gridAdapter.updateCharacter(id, updates) + + // Update with server response + if (this.party?.characters) { + this.party = { + ...this.party, + characters: this.party.characters.map((c) => + String(c.id) === String(id) ? updated : c + ) + } + } + + return updated + } + + /** + * Update a weapon in the party (optimistically updates local state and calls API) + */ + async updateWeapon(id: string, updates: Partial): Promise { + // Optimistically update local state + if (this.party?.weapons) { + this.party = { + ...this.party, + weapons: this.party.weapons.map((w) => + String(w.id) === String(id) ? { ...w, ...updates } : w + ) + } + } + + // Call API + const updated = await gridAdapter.updateWeapon(id, updates) + + // Update with server response + if (this.party?.weapons) { + this.party = { + ...this.party, + weapons: this.party.weapons.map((w) => + String(w.id) === String(id) ? updated : w + ) + } + } + + return updated + } + + clear() { + this.party = null + } +} + +export const partyStore = new PartyStore()