feat: initialize learning platform project with React, Vite, and baseline application structure
This commit is contained in:
116
src/store/AppContext.jsx
Normal file
116
src/store/AppContext.jsx
Normal file
@@ -0,0 +1,116 @@
|
||||
import React, { createContext, useContext, useReducer, useEffect } from 'react';
|
||||
import { storage } from '../lib/storage';
|
||||
|
||||
const AppContext = createContext();
|
||||
|
||||
const initialState = {
|
||||
currentUser: null, // will hold user object if logged in
|
||||
users: [], // array of registered users
|
||||
weekNumber: 1, // current learning week
|
||||
isLoading: true
|
||||
};
|
||||
|
||||
function appReducer(state, action) {
|
||||
switch (action.type) {
|
||||
case 'INIT_APP':
|
||||
return {
|
||||
...state,
|
||||
users: action.payload.users,
|
||||
weekNumber: action.payload.weekNumber,
|
||||
isLoading: false
|
||||
};
|
||||
case 'LOGIN':
|
||||
return {
|
||||
...state,
|
||||
currentUser: action.payload
|
||||
};
|
||||
case 'LOGOUT':
|
||||
return {
|
||||
...state,
|
||||
currentUser: null
|
||||
};
|
||||
case 'REGISTER_USER':
|
||||
return {
|
||||
...state,
|
||||
users: [...state.users, action.payload]
|
||||
};
|
||||
case 'ADVANCE_WEEK':
|
||||
return {
|
||||
...state,
|
||||
weekNumber: state.weekNumber + 1
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export function AppProvider({ children }) {
|
||||
const [state, dispatch] = useReducer(appReducer, initialState);
|
||||
|
||||
// Initialize app state from storage
|
||||
useEffect(() => {
|
||||
const loadState = () => {
|
||||
let users = storage.get('users:registry');
|
||||
|
||||
// Seed first admin if no users exist
|
||||
if (!users || users.length === 0) {
|
||||
const initialAdmin = {
|
||||
id: 'u_1',
|
||||
name: 'Admin',
|
||||
role: 'admin',
|
||||
pin: '0000',
|
||||
registeredAt: new Date().toISOString()
|
||||
};
|
||||
users = [initialAdmin];
|
||||
storage.set('users:registry', users);
|
||||
|
||||
// Also seed initial empty leaderboard
|
||||
storage.set('leaderboard:current', []);
|
||||
}
|
||||
|
||||
const storedWeek = storage.get('admin:current_week') || 1;
|
||||
|
||||
// Automatically login if we saved session (optional, simpler to require login per session)
|
||||
const sessionUserId = sessionStorage.getItem('respellion_session');
|
||||
if (sessionUserId) {
|
||||
const user = users.find(u => u.id === sessionUserId);
|
||||
if (user) {
|
||||
dispatch({ type: 'LOGIN', payload: user });
|
||||
}
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: 'INIT_APP',
|
||||
payload: { users, weekNumber: storedWeek }
|
||||
});
|
||||
};
|
||||
|
||||
loadState();
|
||||
}, []);
|
||||
|
||||
// Expose dispatch actions as convenient methods
|
||||
const login = (userId, pin) => {
|
||||
const user = state.users.find(u => u.id === userId && u.pin === pin);
|
||||
if (user) {
|
||||
sessionStorage.setItem('respellion_session', user.id);
|
||||
dispatch({ type: 'LOGIN', payload: user });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
sessionStorage.removeItem('respellion_session');
|
||||
dispatch({ type: 'LOGOUT' });
|
||||
};
|
||||
|
||||
return (
|
||||
<AppContext.Provider value={{ state, dispatch, login, logout }}>
|
||||
{children}
|
||||
</AppContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useApp() {
|
||||
return useContext(AppContext);
|
||||
}
|
||||
Reference in New Issue
Block a user