feat: implement onboarding process and enrollment status tracking for users

This commit is contained in:
RaymondVerhoef
2026-05-26 21:33:20 +02:00
parent febc9dc7f2
commit 7066f881f9
8 changed files with 225 additions and 34 deletions

View File

@@ -1,40 +1,50 @@
import { createContext, useContext, useReducer, useEffect } from 'react';
import * as db from '../lib/db';
import { pb } from '../lib/pb';
import { getPersonalWeekNumber } from '../lib/curriculumService';
const AppContext = createContext();
const initialState = {
currentUser: null,
users: [],
weekNumber: getWeekNumber(new Date()),
weekNumber: 0,
isLoading: true
};
function computeWeekNumber(user) {
if (!user || !user.curriculum_started_at || user.enrollment_status !== 'active') return 0;
return getPersonalWeekNumber(user.curriculum_started_at);
}
function appReducer(state, action) {
switch (action.type) {
case 'INIT_APP':
return {
...state,
users: action.payload.users,
weekNumber: action.payload.weekNumber || state.weekNumber,
isLoading: false
};
case 'LOGIN':
return { ...state, currentUser: action.payload };
return {
...state,
currentUser: action.payload,
weekNumber: computeWeekNumber(action.payload),
};
case 'UPDATE_CURRENT_USER':
return {
...state,
currentUser: action.payload,
weekNumber: computeWeekNumber(action.payload),
users: state.users.map(u => u.id === action.payload.id ? action.payload : u),
};
case 'LOGOUT':
return { ...state, currentUser: null };
return { ...state, currentUser: null, weekNumber: 0 };
default:
return state;
}
}
function getWeekNumber(d) {
d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay()||7));
const yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
return Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7);
}
export function AppProvider({ children }) {
const [state, dispatch] = useReducer(appReducer, initialState);
@@ -52,8 +62,6 @@ export function AppProvider({ children }) {
}
}
const storedWeek = getWeekNumber(new Date());
const sessionUserId = sessionStorage.getItem('respellion_session');
if (sessionUserId) {
const user = members.find(u => u.id === sessionUserId);
@@ -62,7 +70,7 @@ export function AppProvider({ children }) {
}
}
dispatch({ type: 'INIT_APP', payload: { users: members, weekNumber: storedWeek } });
dispatch({ type: 'INIT_APP', payload: { users: members } });
};
loadState().catch(console.error);
@@ -83,8 +91,23 @@ export function AppProvider({ children }) {
dispatch({ type: 'LOGOUT' });
};
/**
* Start the curriculum for the currently logged-in user.
* Records the start timestamp and flips enrollment_status to 'active'.
*/
const enrollCurrentUser = async () => {
if (!state.currentUser) throw new Error('No user is logged in.');
const startedAt = new Date().toISOString();
const updated = await pb.collection('team_members').update(state.currentUser.id, {
curriculum_started_at: startedAt,
enrollment_status: 'active',
});
dispatch({ type: 'UPDATE_CURRENT_USER', payload: updated });
return updated;
};
return (
<AppContext.Provider value={{ state, dispatch, login, logout }}>
<AppContext.Provider value={{ state, dispatch, login, logout, enrollCurrentUser }}>
{children}
</AppContext.Provider>
);