test: added SimpleProgram #37

Closed
2584433 wants to merge 9 commits from feat/simple-program-page into demo
Showing only changes of commit d80ced547c - Show all commits

View File

@@ -2,41 +2,6 @@ import React from "react";
import styles from "./SimpleProgram.module.css"; import styles from "./SimpleProgram.module.css";
import useProgramStore from "../../utils/programStore.ts"; import useProgramStore from "../../utils/programStore.ts";
/* ---------- Types ---------- */
type Norm = {
id: string;
label: string;
norm: string;
};
type Goal = {
id: string;
label: string;
description: string;
achieved: boolean;
};
type TriggerKeyword = {
id: string;
keyword: string;
};
type KeywordTrigger = {
id: string;
label: string;
type: string;
keywords: TriggerKeyword[];
};
type Phase = {
id: string;
label: string;
norms: Norm[];
goals: Goal[];
triggers: KeywordTrigger[];
};
/* ---------- Reusable UI ---------- */ /* ---------- Reusable UI ---------- */
type BoxProps = { type BoxProps = {
@@ -53,70 +18,111 @@ const Box: React.FC<BoxProps> = ({ title, children }) => (
/* ---------- Lists ---------- */ /* ---------- Lists ---------- */
const GoalList: React.FC<{ goals: Goal[] }> = ({ goals }) => { const GoalList: React.FC<{ goals: unknown[] }> = ({ goals }) => {
if (goals.length === 0) return <p className={styles.empty}>No goals defined.</p>; if (!goals.length) {
return <p className={styles.empty}>No goals defined.</p>;
}
return ( return (
<ul className={styles.iconList}> <ul className={styles.iconList}>
{goals.map((goal) => ( {goals.map((g, idx) => {
<li key={goal.id}> const goal = g as {
<span className={goal.achieved ? styles.successIcon : styles.failIcon}> id?: string;
description?: string;
achieved?: boolean;
};
return (
<li key={goal.id ?? idx}>
<span
className={
goal.achieved ? styles.successIcon : styles.failIcon
}
>
{goal.achieved ? "✔" : "✖"} {goal.achieved ? "✔" : "✖"}
</span> </span>
{goal.description} {goal.description ?? "Unnamed goal"}
</li> </li>
))} );
})}
</ul> </ul>
); );
}; };
const TriggerList: React.FC<{ triggers: KeywordTrigger[] }> = ({ triggers }) => { const TriggerList: React.FC<{ triggers: unknown[] }> = ({ triggers }) => {
if (triggers.length === 0) return <p className={styles.empty}>No triggers defined.</p>; if (!triggers.length) {
return <p className={styles.empty}>No triggers defined.</p>;
}
return ( return (
<ul className={styles.iconList}> <ul className={styles.iconList}>
{triggers.map((trigger) => ( {triggers.map((t, idx) => {
<li key={trigger.id}> const trigger = t as {
id?: string;
label?: string;
};
return (
<li key={trigger.id ?? idx}>
<span className={styles.failIcon}></span> <span className={styles.failIcon}></span>
{trigger.label} {trigger.label ?? "Unnamed trigger"}
</li> </li>
))} );
})}
</ul> </ul>
); );
}; };
const NormList: React.FC<{ norms: Norm[] }> = ({ norms }) => { const NormList: React.FC<{ norms: unknown[] }> = ({ norms }) => {
if (norms.length === 0) return <p className={styles.empty}>No norms defined.</p>; if (!norms.length) {
return <p className={styles.empty}>No norms defined.</p>;
}
return ( return (
<ul className={styles.bulletList}> <ul className={styles.bulletList}>
{norms.map((norm) => ( {norms.map((n, idx) => {
<li key={norm.id}>{norm.norm}</li> const norm = n as {
))} id?: string;
norm?: string;
};
return <li key={norm.id ?? idx}>{norm.norm ?? "Unnamed norm"}</li>;
})}
</ul> </ul>
); );
}; };
/* ---------- Phase Grid ---------- */ /* ---------- Phase Grid ---------- */
const PhaseGrid: React.FC<{ phase: Phase }> = ({ phase }) => { type PhaseGridProps = {
norms: unknown[];
goals: unknown[];
triggers: unknown[];
};
const PhaseGrid: React.FC<PhaseGridProps> = ({
norms,
goals,
triggers,
}) => {
return ( return (
<div className={styles.phaseGrid}> <div className={styles.phaseGrid}>
<Box title="Norms"> <Box title="Norms">
<NormList norms={phase.norms} /> <NormList norms={norms} />
</Box> </Box>
<Box title="Triggers"> <Box title="Triggers">
<TriggerList triggers={phase.triggers} /> <TriggerList triggers={triggers} />
</Box> </Box>
<Box title="Goals"> <Box title="Goals">
<GoalList goals={phase.goals} /> <GoalList goals={goals} />
</Box> </Box>
<Box title="Conditional Norms"> <Box title="Conditional Norms">
<p className={styles.empty}>No conditional norms defined.</p> <p className={styles.empty}>No conditional norms defined.</p>
</Box> </Box>
{/* Let er dus op dat deze erbij moeten */}
</div> </div>
); );
}; };
@@ -124,35 +130,50 @@ const PhaseGrid: React.FC<{ phase: Phase }> = ({ phase }) => {
/* ---------- Main Component ---------- */ /* ---------- Main Component ---------- */
const SimpleProgram: React.FC = () => { const SimpleProgram: React.FC = () => {
// Get the phases from the program store const getPhaseIds = useProgramStore((s) => s.getPhaseIds);
const phases = useProgramStore((state) => state.currentProgram.phases) as Phase[]; const getNormsInPhase = useProgramStore((s) => s.getNormsInPhase);
const getGoalsInPhase = useProgramStore((s) => s.getGoalsInPhase);
const getTriggersInPhase = useProgramStore((s) => s.getTriggersInPhase);
const phaseIds = getPhaseIds();
const [phaseIndex, setPhaseIndex] = React.useState(0); const [phaseIndex, setPhaseIndex] = React.useState(0);
// If no phases are available, display a message if (phaseIds.length === 0) {
if (phases.length === 0) return <p className={styles.empty}>No program loaded.</p>; return <p className={styles.empty}>No program loaded.</p>;
}
const phase = phases[phaseIndex]; const phaseId = phaseIds[phaseIndex];
return ( return (
<div className={styles.container}> <div className={styles.container}>
<header className={styles.header}> <header className={styles.header}>
<h2> <h2>
Phase {phaseIndex + 1} / {phases.length}: {phase.label} Phase {phaseIndex + 1} / {phaseIds.length}
</h2> </h2>
<div className={styles.controls}> <div className={styles.controls}>
<button disabled={phaseIndex === 0} onClick={() => setPhaseIndex(i => i - 1)}> <button
disabled={phaseIndex === 0}
onClick={() => setPhaseIndex((i) => i - 1)}
>
Prev Prev
</button> </button>
<button disabled={phaseIndex === phases.length - 1} onClick={() => setPhaseIndex(i => i + 1)}> <button
disabled={phaseIndex === phaseIds.length - 1}
onClick={() => setPhaseIndex((i) => i + 1)}
>
Next Next
</button> </button>
</div> </div>
</header> </header>
<div className={styles.content}> <div className={styles.content}>
<PhaseGrid phase={phase} /> <PhaseGrid
norms={getNormsInPhase(phaseId)}
goals={getGoalsInPhase(phaseId)}
triggers={getTriggersInPhase(phaseId)}
/>
</div> </div>
</div> </div>
); );