feat: migrate app state to bootstrap endpoint
app-ci-deploy / test-build-deploy (push) Has been cancelled
app-ci-deploy / test-build-deploy (push) Has been cancelled
Use GET /me/bootstrap as the primary authenticated state source per ADR-0003. AuthContext now fetches and exposes typed bootstrapData, Header and class/detail admin checks use bootstrap permissions/roles, dashboard surfaces onboarding/calendar/timetable/graph status, and graph navigation derives school setup state from bootstrap instead of /school/status. Refs: t_44353587
This commit is contained in:
@@ -483,11 +483,10 @@ function TreeItem({ node, depth, onSelect, onExpand }: TreeItemProps) {
|
||||
// ─── Main Panel ───────────────────────────────────────────────────────────────
|
||||
|
||||
export function CCGraphNavPanel() {
|
||||
const { accessToken } = useAuth();
|
||||
const { accessToken, bootstrapData } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const { navigateToNeoNode, context } = useNavigationStore();
|
||||
const [tree, setTree] = useState<TreeNode | null>(null);
|
||||
const [schoolStatus, setSchoolStatus] = useState<SchoolStatus | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
@@ -526,19 +525,31 @@ export function CCGraphNavPanel() {
|
||||
}
|
||||
}, [accessToken, apiBase]);
|
||||
|
||||
const fetchSchoolStatus = useCallback(async () => {
|
||||
if (!accessToken) return;
|
||||
try {
|
||||
const res = await fetch(`${apiBase}/school/status`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
if (!res.ok) return;
|
||||
const data = await res.json();
|
||||
setSchoolStatus(data);
|
||||
} catch {
|
||||
// non-fatal — panel still works without school status
|
||||
}
|
||||
}, [accessToken, apiBase]);
|
||||
const schoolStatus = useMemo<SchoolStatus | null>(() => {
|
||||
if (!bootstrapData) return null;
|
||||
const membershipRole = bootstrapData.active_institute?.membership_role ?? undefined;
|
||||
const activeMembership = bootstrapData.memberships?.find(
|
||||
(m) => m.institute_id === bootstrapData.active_institute?.id && m.is_active
|
||||
);
|
||||
return {
|
||||
status: bootstrapData.school_status,
|
||||
user_role: membershipRole,
|
||||
school_id: bootstrapData.active_institute?.id ?? undefined,
|
||||
school_has_calendar: bootstrapData.calendar_status.available && !bootstrapData.calendar_status.needs_setup,
|
||||
teacher_has_timetable: bootstrapData.timetable_status.available && !bootstrapData.timetable_status.needs_setup,
|
||||
timetable_id: bootstrapData.timetable_status.teacher_timetable_id,
|
||||
periods_template: [],
|
||||
school_info: activeMembership?.institute ? {
|
||||
name: activeMembership.institute.name,
|
||||
urn: activeMembership.institute.urn ?? '',
|
||||
website: '',
|
||||
address: {},
|
||||
headteacher: '',
|
||||
term_dates_url: '',
|
||||
staff_list_url: '',
|
||||
} : undefined,
|
||||
};
|
||||
}, [bootstrapData]);
|
||||
|
||||
useEffect(() => {
|
||||
if (accessToken && !tree) fetchTree();
|
||||
@@ -553,9 +564,6 @@ export function CCGraphNavPanel() {
|
||||
}
|
||||
}, [tree]);
|
||||
|
||||
useEffect(() => {
|
||||
if (accessToken && !schoolStatus) fetchSchoolStatus();
|
||||
}, [accessToken, schoolStatus, fetchSchoolStatus]);
|
||||
|
||||
// Fetch timetable term nodes when switching to term view
|
||||
useEffect(() => {
|
||||
@@ -637,7 +645,6 @@ export function CCGraphNavPanel() {
|
||||
|
||||
const refreshAll = useCallback(() => {
|
||||
setTree(null);
|
||||
setSchoolStatus(null);
|
||||
setAcademicCalendarStatus('idle');
|
||||
setAcademicTerms([]);
|
||||
}, []);
|
||||
@@ -726,9 +733,8 @@ export function CCGraphNavPanel() {
|
||||
onClose={() => setOnboardingWizardOpen(false)}
|
||||
onComplete={() => {
|
||||
setOnboardingWizardOpen(false);
|
||||
// Reload tree + school status after successful onboarding
|
||||
// Reload tree after successful onboarding; bootstrap state refreshes from AuthContext
|
||||
setTree(null);
|
||||
setSchoolStatus(null);
|
||||
}}
|
||||
apiBase={apiBase}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user