feat: implement knowledge testing system with leaderboard, quiz generation, and PocketBase integration
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import React, { createContext, useContext, useReducer, useEffect } from 'react';
|
||||
import { storage } from '../lib/storage';
|
||||
import * as db from '../lib/db';
|
||||
|
||||
const AppContext = createContext();
|
||||
|
||||
const initialState = {
|
||||
currentUser: null, // will hold user object if logged in
|
||||
users: [], // array of registered users
|
||||
weekNumber: 1, // current learning week
|
||||
currentUser: null,
|
||||
users: [],
|
||||
weekNumber: 1,
|
||||
isLoading: true
|
||||
};
|
||||
|
||||
@@ -20,25 +20,11 @@ function appReducer(state, action) {
|
||||
isLoading: false
|
||||
};
|
||||
case 'LOGIN':
|
||||
return {
|
||||
...state,
|
||||
currentUser: action.payload
|
||||
};
|
||||
return { ...state, currentUser: action.payload };
|
||||
case 'LOGOUT':
|
||||
return {
|
||||
...state,
|
||||
currentUser: null
|
||||
};
|
||||
case 'REGISTER_USER':
|
||||
return {
|
||||
...state,
|
||||
users: [...state.users, action.payload]
|
||||
};
|
||||
return { ...state, currentUser: null };
|
||||
case 'ADVANCE_WEEK':
|
||||
return {
|
||||
...state,
|
||||
weekNumber: state.weekNumber + 1
|
||||
};
|
||||
return { ...state, weekNumber: state.weekNumber + 1 };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
@@ -47,48 +33,31 @@ function appReducer(state, action) {
|
||||
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;
|
||||
const loadState = async () => {
|
||||
let members = await db.getTeamMembers();
|
||||
|
||||
if (!members || members.length === 0) {
|
||||
const created = await db.addTeamMember({ name: 'Admin', role: 'admin', pin: '0000' });
|
||||
members = [created];
|
||||
}
|
||||
|
||||
const storedWeek = Number(await db.getSetting('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);
|
||||
const user = members.find(u => u.id === sessionUserId);
|
||||
if (user) {
|
||||
dispatch({ type: 'LOGIN', payload: user });
|
||||
}
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: 'INIT_APP',
|
||||
payload: { users, weekNumber: storedWeek }
|
||||
});
|
||||
dispatch({ type: 'INIT_APP', payload: { users: members, weekNumber: storedWeek } });
|
||||
};
|
||||
|
||||
loadState();
|
||||
loadState().catch(console.error);
|
||||
}, []);
|
||||
|
||||
// Expose dispatch actions as convenient methods
|
||||
const login = (userId, pin) => {
|
||||
const user = state.users.find(u => u.id === userId && u.pin === pin);
|
||||
if (user) {
|
||||
|
||||
Reference in New Issue
Block a user