Skip to content

Commit ecad127

Browse files
committed
Add global app state management with context
Introduces AppProvider and related hooks for managing global application state using React context and reducer. Supports loading, error handling, and player data access throughout the app.
1 parent db9ee91 commit ecad127

1 file changed

Lines changed: 67 additions & 0 deletions

File tree

src/state/appStore.tsx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import React, { createContext, useContext, useMemo, useReducer } from 'react';
2+
import type { fullPlayerDataType } from 'types/displayDataTypes';
3+
4+
export type LoadStatus = 'idle' | 'loading' | 'ready' | 'error';
5+
6+
interface AppState {
7+
status: LoadStatus;
8+
loadedAt?: number;
9+
saveSignature?: string;
10+
players: fullPlayerDataType[];
11+
error?: string;
12+
}
13+
14+
const initialState: AppState = {
15+
status: 'idle',
16+
players: [],
17+
};
18+
19+
type AppAction =
20+
| { type: 'loadSaveRequested'; payload?: { fileName?: string } }
21+
| { type: 'loadSaveSucceeded'; payload: { saveSignature: string; players: fullPlayerDataType[] } }
22+
| { type: 'loadSaveFailed'; payload: { error: string | undefined } }
23+
| { type: 'clearSave' };
24+
25+
function appReducer(state: AppState, action: AppAction): AppState {
26+
switch (action.type) {
27+
case 'loadSaveRequested':
28+
return { ...state, status: 'loading' };
29+
case 'loadSaveSucceeded':
30+
return {
31+
status: 'ready',
32+
loadedAt: Date.now(),
33+
saveSignature: action.payload.saveSignature,
34+
players: action.payload.players,
35+
};
36+
case 'loadSaveFailed':
37+
return { ...state, status: 'error', error: action.payload.error ?? undefined };
38+
case 'clearSave':
39+
return { ...initialState };
40+
default:
41+
return state;
42+
}
43+
}
44+
45+
const AppContext = createContext<{ state: AppState; dispatch: React.Dispatch<AppAction> } | undefined>(undefined);
46+
47+
export const AppProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
48+
const [state, dispatch] = useReducer(appReducer, initialState);
49+
const value = useMemo(() => ({ state, dispatch }), [state]);
50+
return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
51+
};
52+
53+
export const useAppStore = () => {
54+
const ctx = useContext(AppContext);
55+
if (!ctx) throw new Error('useAppStore must be used within AppProvider');
56+
return ctx;
57+
};
58+
59+
export const useAppSelector = <T,>(select: (s: AppState) => T): T => {
60+
const { state } = useAppStore();
61+
return select(state);
62+
};
63+
64+
// Example selectors
65+
export const usePlayers = () => useAppSelector(s => s.players);
66+
export const useLoadStatus = () => useAppSelector(s => s.status);
67+
export const usePlayerByName = (name: string) => useAppSelector(s => s.players.find(p => p.playerName === name));

0 commit comments

Comments
 (0)