import { createContext } from 'react'; import { createStore, StateCreator } from 'zustand'; import { doesExist, Maybe } from '@apextoaster/js-utils'; import { PaletteMode } from '@mui/material'; import { ReadyState } from 'react-use-websocket'; import { Actor, GameEvent, Item, Room, World } from './models'; export type LayoutMode = 'horizontal' | 'vertical'; export interface ClientState { autoScroll: boolean; clientId: string; clientName: string; detailEntity: Maybe; eventHistory: Array; layoutMode: LayoutMode; readyState: ReadyState; themeMode: PaletteMode; // setters setAutoScroll: (autoScroll: boolean) => void; setClientId: (clientId: string) => void; setClientName: (name: string) => void; setDetailEntity: (entity: Maybe) => void; setLayoutMode: (mode: LayoutMode) => void; setReadyState: (state: ReadyState) => void; setThemeMode: (mode: PaletteMode) => void; // misc helpers appendEvent: (event: GameEvent) => void; clearDetailEntity: () => void; clearEventHistory: () => void; } export interface WorldState { players: Record; world: Maybe; // setters setPlayers: (players: Record) => void; setWorld: (world: Maybe) => void; } export interface PlayerState { activeTurn: boolean; character: Maybe; // setters setActiveTurn: (activeTurn: boolean) => void; setCharacter: (character: Maybe) => void; // misc helpers isPlaying: () => boolean; } export type StoreState = ClientState & WorldState & PlayerState; export function createClientStore(): StateCreator { return (set) => ({ autoScroll: true, clientId: '', clientName: '', detailEntity: undefined, eventHistory: [], layoutMode: 'horizontal', readyState: ReadyState.UNINSTANTIATED, themeMode: 'light', setAutoScroll(autoScroll) { set({ autoScroll }); }, setClientId(clientId) { set({ clientId }); }, setClientName(clientName) { set({ clientName }); }, setDetailEntity(detailEntity) { set({ detailEntity }); }, setLayoutMode(mode) { set({ layoutMode: mode }); }, setReadyState(state) { set({ readyState: state }); }, setThemeMode(themeMode) { set({ themeMode }); }, appendEvent(event) { set((state) => { const history = state.eventHistory.concat(event); return { eventHistory: history }; }); }, clearDetailEntity() { set({ detailEntity: undefined }); }, clearEventHistory() { set({ eventHistory: [] }); }, }); } export function createWorldStore(): StateCreator { return (set) => ({ players: {}, world: undefined, setPlayers: (players) => set({ players }), setWorld: (world) => set({ world }), }); } export function createPlayerStore(): StateCreator { return (set) => ({ activeTurn: false, character: undefined, setActiveTurn: (activeTurn: boolean) => set({ activeTurn }), setCharacter: (character: Maybe) => set({ character }), isPlaying() { return doesExist(this.character); }, }); } export function createStateStore() { return createStore((...args) => ({ ...createClientStore()(...args), ...createWorldStore()(...args), ...createPlayerStore()(...args), })); } // TODO: make this not global export const store = createStateStore(); export const storeContext = createContext(store);