feat: The Big One UI

This commit is contained in:
Gerla, J. (Justin)
2026-01-28 08:27:30 +00:00
committed by Pim Hutting
parent f9e0eb95f8
commit 82785dc8cb
45 changed files with 4147 additions and 143 deletions

View File

@@ -3,6 +3,8 @@ import {create} from "zustand";
// the type of a reduced program
export type ReducedProgram = { phases: Record<string, unknown>[] };
export type GoalWithDepth = Record<string, unknown> & { level: number };
/**
* the type definition of the programStore
*/
@@ -15,8 +17,10 @@ export type ProgramState = {
// Utility functions:
// to avoid having to manually go through the entire state for every instance where data is required
getPhaseIds: () => string[];
getPhaseNames: () => string[];
getNormsInPhase: (currentPhaseId: string) => Record<string, unknown>[];
getGoalsInPhase: (currentPhaseId: string) => Record<string, unknown>[];
getGoalsWithDepth: (currentPhaseId: string) => GoalWithDepth[];
getTriggersInPhase: (currentPhaseId: string) => Record<string, unknown>[];
// if more specific utility functions are needed they can be added here:
}
@@ -43,6 +47,10 @@ const useProgramStore = create<ProgramState>((set, get) => ({
* gets the ids of all phases in the program
*/
getPhaseIds: () => get().currentProgram.phases.map(entry => entry["id"] as string),
/**
* gets the names of all phases in the program
*/
getPhaseNames: () => get().currentProgram.phases.map((entry) => (entry["name"] as string)),
/**
* gets the norms for the provided phase
*/
@@ -65,6 +73,50 @@ const useProgramStore = create<ProgramState>((set, get) => ({
}
throw new Error(`phase with id:"${currentPhaseId}" not found`)
},
getGoalsWithDepth: (currentPhaseId: string) => {
const program = get().currentProgram;
const phase = program.phases.find(val => val["id"] === currentPhaseId);
if (!phase) {
throw new Error(`phase with id:"${currentPhaseId}" not found`);
}
const rootGoals = phase["goals"] as Record<string, unknown>[];
const flatList: GoalWithDepth[] = [];
const isGoal = (item: Record<string, unknown>) => {
return item["plan"] !== undefined;
};
// Recursive helper function
const traverse = (goals: Record<string, unknown>[], depth: number) => {
goals.forEach((goal) => {
// 1. Add the current goal to the list
flatList.push({ ...goal, level: depth });
// 2. Check for children
const plan = goal["plan"] as Record<string, unknown> | undefined;
if (plan && Array.isArray(plan["steps"])) {
const steps = plan["steps"] as Record<string, unknown>[];
// 3. FILTER: Only recurse on steps that are actually goals
// If we just passed 'steps', we might accidentally add Actions/Speeches to the goal list
const childGoals = steps.filter(isGoal);
if (childGoals.length > 0) {
traverse(childGoals, depth + 1);
}
}
});
};
// Start traversal
traverse(rootGoals, 0);
return flatList;
},
/**
* gets the triggers for the provided phase
*/