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

@@ -3,17 +3,36 @@ import { callLLM, cachedSystem } from './llm';
import { EMIT_CURRICULUM_SCHEDULE_TOOL, EMIT_TOPIC_ENRICHMENT_TOOL } from './llmTools';
/**
* Get the current curriculum week (1-26) based on an ISO week number.
* Personal weeks since enrollment, starting at 1.
* Cycle is purely relative: week 1 = first 7 days after start_date.
* Returns 0 if the user has not yet enrolled.
*/
export function getCurriculumWeek(isoWeekNumber) {
return ((isoWeekNumber - 1) % 26) + 1;
export function getPersonalWeekNumber(startedAt, now = new Date()) {
if (!startedAt) return 0;
const start = startedAt instanceof Date ? startedAt : new Date(startedAt);
if (Number.isNaN(start.getTime())) return 0;
const elapsedMs = now.getTime() - start.getTime();
if (elapsedMs < 0) return 0;
const days = Math.floor(elapsedMs / 86_400_000);
return Math.floor(days / 7) + 1;
}
/**
* Get the current curriculum cycle (1, 2, 3...) based on an ISO week number.
* Curriculum slot (1-26) for a given personal week number.
* weekNumber is the absolute counter from getPersonalWeekNumber — it loops
* through the 26-slot schedule indefinitely.
*/
export function getCurriculumCycle(isoWeekNumber) {
return Math.floor((isoWeekNumber - 1) / 26) + 1;
export function getCurriculumWeek(weekNumber) {
if (!weekNumber || weekNumber < 1) return 0;
return ((weekNumber - 1) % 26) + 1;
}
/**
* Cycle (1, 2, 3...) for a given personal week number.
*/
export function getCurriculumCycle(weekNumber) {
if (!weekNumber || weekNumber < 1) return 0;
return Math.floor((weekNumber - 1) / 26) + 1;
}
/**
@@ -284,16 +303,17 @@ export async function getVersionHistory() {
}
/**
* Get the assigned topics and metadata for a given ISO week number.
* Get the assigned topics and metadata for a given personal week number.
*/
export async function getCurrentWeekContent(isoWeekNumber) {
export async function getCurrentWeekContent(personalWeekNumber) {
const activeVersion = await db.getActiveCurriculumVersion();
if (!activeVersion || !activeVersion.schedule) {
return null;
}
const weekNumber = getCurriculumWeek(isoWeekNumber);
const cycle = getCurriculumCycle(isoWeekNumber);
const weekNumber = getCurriculumWeek(personalWeekNumber);
const cycle = getCurriculumCycle(personalWeekNumber);
if (weekNumber < 1) return null;
const scheduleWeek = activeVersion.schedule.find(w => w.week_number === weekNumber);
if (!scheduleWeek) return null;
@@ -317,13 +337,14 @@ export async function getCurrentWeekContent(isoWeekNumber) {
/**
* Track progress for the current cycle based on completed weeks.
*/
export async function getYearProgress(userId, isoWeekNumber) {
export async function getYearProgress(userId, personalWeekNumber) {
const activeVersion = await db.getActiveCurriculumVersion();
if (!activeVersion) {
return { completed: 0, total: 26, percentage: 0 };
}
const currentCycle = getCurriculumCycle(isoWeekNumber);
const currentCycle = getCurriculumCycle(personalWeekNumber);
if (currentCycle < 1) return { completed: 0, total: 26, percentage: 0 };
const cycleStartWeek = (currentCycle - 1) * 26 + 1;
const cycleEndWeek = currentCycle * 26;