Function bodies 11 total
App function · javascript · L13-L127 (115 LOC)src/App.jsx
function App() {
const [selectedModule, setSelectedModule] = useState(0);
const [activeTab, setActiveTab] = useState('overview');
const [scenarioAnswers, setScenarioAnswers] = useState({});
const [quizAnswers, setQuizAnswers] = useState({});
const [quizSubmitted, setQuizSubmitted] = useState({});
const { completedModules, markComplete, reset } = useProgress();
const currentModule = modules[selectedModule];
const handleModuleSelect = (idx) => {
setSelectedModule(idx);
setActiveTab('overview');
};
const handleReset = () => {
if (window.confirm('Reset all progress? This cannot be undone.')) {
reset();
setScenarioAnswers({});
setQuizAnswers({});
setQuizSubmitted({});
}
};
const handleScenarioAnswer = (scenarioId, optionIndex) => {
if (optionIndex === undefined) {
setScenarioAnswers((prev) => {
const next = { ...prev };
delete next[scenarioId];
return next;
});
} else {
setSModuleChart function · javascript · L17-L123 (107 LOC)src/charts/ModuleChart.jsx
export default function ModuleChart({ data, type, label, moduleId }) {
if (type === 'bar') {
// Check if data has multiple numeric keys (grouped bar)
const sampleItem = data[0] || {};
const numericKeys = Object.keys(sampleItem).filter(
(k) => k !== 'name' && typeof sampleItem[k] === 'number'
);
const isGrouped = numericKeys.length > 1;
const colors = ['#ffcb05', '#60a5fa', '#4ade80', '#c084fc'];
return (
<ResponsiveContainer width="100%" height={280}>
<BarChart data={data} margin={{ top: 5, right: 20, bottom: 5, left: 0 }}>
<CartesianGrid strokeDasharray="3 3" stroke="#1e3a5f" />
<XAxis
dataKey="name"
tick={{ fill: '#94a3b8', fontSize: 11 }}
axisLine={{ stroke: '#1e3a5f' }}
tickLine={{ stroke: '#1e3a5f' }}
/>
<YAxis
tick={{ fill: '#94a3b8', fontSize: 11 }}
axisLine={{ stroke: '#1e3a5f' }}
tickLine={{ stroke: '#1eHeader function · javascript · L12-L158 (147 LOC)src/components/Header.jsx
export default function Header({ module, activeTab, onTabChange }) {
const Icon = module.icon;
return (
<div style={{ borderBottom: '1px solid #1e3a5f' }}>
{/* Title bar */}
<div style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'flex-start',
padding: '20px 32px 12px',
}}>
<div style={{ display: 'flex', gap: 14, alignItems: 'flex-start' }}>
<div style={{
width: 40,
height: 40,
background: '#0f2744',
borderRadius: 10,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<Icon size={20} color="#ffcb05" />
</div>
<div>
<h1 style={{ fontSize: 20, fontWeight: 700, color: '#e2e8f0', margin: 0, lineHeight: 1.2 }}>
{module.title}
</h1>
<p style={{ fontSize: 13, color: '#94a3b8', margin: '4px 0 0' }}>
Sidebar function · javascript · L5-L251 (247 LOC)src/components/Sidebar.jsx
export default function Sidebar({ modules, selectedModule, onSelect, completedModules, onReset }) {
const completedCount = completedModules.size;
const progress = (completedCount / modules.length) * 100;
const [collapsed, setCollapsed] = useState({});
const togglePillar = (pillarId) => {
setCollapsed((prev) => ({ ...prev, [pillarId]: !prev[pillarId] }));
};
// Group modules by pillar
const grouped = {};
modules.forEach((mod, idx) => {
const key = mod.pillar || 'other';
if (!grouped[key]) grouped[key] = [];
grouped[key].push({ mod, idx });
});
// Order groups by pillars array
const orderedGroups = pillars
.filter((p) => grouped[p.id])
.map((p) => ({ pillar: p, items: grouped[p.id] }));
return (
<div style={{
width: 280,
minWidth: 280,
background: '#0a1628',
borderRight: '1px solid #1e3a5f',
display: 'flex',
flexDirection: 'column',
height: '100vh',
overflow: 'hidden',
}}>
{ChartTab function · javascript · L3-L24 (22 LOC)src/components/tabs/ChartTab.jsx
export default function ChartTab({ module }) {
return (
<div style={{ maxWidth: 720 }}>
<div style={{
background: '#0a1628',
border: '1px solid #1e3a5f',
borderRadius: 12,
padding: 24,
}}>
<h3 style={{ fontSize: 16, fontWeight: 700, color: '#e2e8f0', marginBottom: 20 }}>
{module.chartLabel}
</h3>
<ModuleChart
data={module.chartData}
type={module.chartType}
label={module.chartLabel}
moduleId={module.id}
/>
</div>
</div>
);
}ConceptsTab function · javascript · L1-L30 (30 LOC)src/components/tabs/ConceptsTab.jsx
export default function ConceptsTab({ module }) {
return (
<div style={{ maxWidth: 720 }}>
<h3 style={{ fontSize: 16, fontWeight: 700, color: '#e2e8f0', marginBottom: 16 }}>
Key Concepts
</h3>
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
{module.concepts.map((concept, idx) => (
<div
key={idx}
style={{
background: '#0a1628',
border: '1px solid #1e3a5f',
borderRadius: 12,
padding: 20,
borderLeft: '3px solid #ffcb05',
}}
>
<h4 style={{ fontSize: 14, fontWeight: 700, color: '#e2e8f0', marginBottom: 6 }}>
{concept.name}
</h4>
<p style={{ fontSize: 13, lineHeight: 1.6, color: '#94a3b8', margin: 0 }}>
{concept.desc}
</p>
</div>
))}
</div>
</div>
);
}OverviewTab function · javascript · L3-L87 (85 LOC)src/components/tabs/OverviewTab.jsx
export default function OverviewTab({ module }) {
return (
<div style={{ maxWidth: 720 }}>
<div style={{
background: '#0a1628',
border: '1px solid #1e3a5f',
borderRadius: 12,
padding: 24,
marginBottom: 20,
}}>
<h3 style={{ fontSize: 16, fontWeight: 700, color: '#e2e8f0', marginBottom: 12 }}>
Module Overview
</h3>
<p style={{ fontSize: 14, lineHeight: 1.7, color: '#94a3b8' }}>
{module.overview}
</p>
</div>
{/* Learning Objectives */}
{module.learningObjectives && module.learningObjectives.length > 0 && (
<div style={{
background: '#0a1628',
border: '1px solid #1e3a5f',
borderRadius: 12,
padding: 24,
marginBottom: 20,
}}>
<div style={{ display: 'flex', gap: 10, alignItems: 'center', marginBottom: 16 }}>
<Target size={18} color="#60a5fa" />
<h3 style={{ fontSize: Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
QuizTab function · javascript · L3-L201 (199 LOC)src/components/tabs/QuizTab.jsx
export default function QuizTab({ module, quizAnswers, quizSubmitted, onQuizAnswer, onQuizSubmit, onQuizRetake }) {
const quiz = module.quiz;
const moduleId = module.id;
const isSubmitted = quizSubmitted[moduleId];
const allAnswered = quiz.every((_, idx) => quizAnswers[`${moduleId}-${idx}`] !== undefined);
const passingThreshold = 0.8;
let score = 0;
if (isSubmitted) {
quiz.forEach((q, idx) => {
if (quizAnswers[`${moduleId}-${idx}`] === q.answer) score++;
});
}
const percentage = Math.round((score / quiz.length) * 100);
const passed = percentage >= passingThreshold * 100;
return (
<div style={{ maxWidth: 720 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 }}>
<div>
<h3 style={{ fontSize: 16, fontWeight: 700, color: '#e2e8f0', margin: 0 }}>
Knowledge Check
</h3>
<p style={{ fontSize: 12, color: '#64748b', margin: '4px 0 0' }}>
ScenariosTab function · javascript · L3-L118 (116 LOC)src/components/tabs/ScenariosTab.jsx
export default function ScenariosTab({ module, scenarioAnswers, onAnswer }) {
return (
<div style={{ maxWidth: 720, display: 'flex', flexDirection: 'column', gap: 24 }}>
{module.scenarios.map((scenario) => {
const answered = scenarioAnswers[scenario.id] !== undefined;
const selectedIdx = scenarioAnswers[scenario.id];
const correctIdx = scenario.options.findIndex((o) => o.correct);
return (
<div
key={scenario.id}
style={{
background: '#0a1628',
border: '1px solid #1e3a5f',
borderRadius: 12,
padding: 24,
}}
>
<div style={{
fontSize: 10,
fontWeight: 700,
color: '#60a5fa',
textTransform: 'uppercase',
letterSpacing: '0.1em',
marginBottom: 12,
}}>
Executive Scenario
</div>
<p style={{ fontSize:VideoTab function · javascript · L1-L55 (55 LOC)src/components/tabs/VideoTab.jsx
export default function VideoTab({ module }) {
return (
<div style={{ maxWidth: 800, display: 'flex', flexDirection: 'column', gap: 24 }}>
{module.videos.map((video, idx) => (
<div
key={idx}
style={{
background: '#0a1628',
border: '1px solid #1e3a5f',
borderRadius: 12,
padding: 20,
}}
>
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
<h4 style={{ fontSize: 15, fontWeight: 700, color: '#e2e8f0', margin: 0, flex: 1 }}>
{video.title}
</h4>
<span style={{
fontSize: 10,
padding: '3px 8px',
borderRadius: 4,
background: '#1e3a5f',
color: '#60a5fa',
fontWeight: 600,
whiteSpace: 'nowrap',
}}>
{video.source}
</span>
<span style={{
fontSize:useProgress function · javascript · L3-L26 (24 LOC)src/hooks/useProgress.js
export function useProgress() {
const [completedModules, setCompletedModules] = useState(() => {
try {
const stored = localStorage.getItem('cdaio-completed');
return stored ? new Set(JSON.parse(stored)) : new Set();
} catch {
return new Set();
}
});
useEffect(() => {
localStorage.setItem('cdaio-completed', JSON.stringify([...completedModules]));
}, [completedModules]);
const markComplete = (id) => {
setCompletedModules((prev) => new Set([...prev, id]));
};
const reset = () => {
setCompletedModules(new Set());
};
return { completedModules, markComplete, reset };
}