Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1x 2x 2x | import { Suspense, useEffect } from "react";
import { Outlet } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { Box } from "@mui/material";
import { ThemeToggleProvider } from "@/theme/ThemeContext";
import SimpleLoading from "@/utils/components/SimpleLoading";
import ThemePresets from "@/utils/components/theme-sets/presets/ThemePresets";
import IdleChecker from "@/utils/components/idle-checker/IdleChecker";
import Copyright from "@/utils/components/copyright/Copyright";
import GlobalMaintenanceBanner from "@/utils/components/feature-access/GlobalMaintenanceBanner";
import { UpgradeDialogProvider } from "@/utils/components/feature-access/UpgradeDialogProvider";
import { _studentGetData } from "@/store/slices/student/StudentData";
import { fetchStudentDistrictFeatures, fetchStudentOrganization } from "@/store/slices/student/StudentFeatureFlags";
import { _fetchStudentTheme } from "@/store/slices/student/StudentThemes";
import { useFeatureFlag } from "@/utils/hooks/useFeatureFlag";
import AppLayout from "./layout/AppLayout";
export default function StudentMainPage() {
const { isLoading } = useSelector((state) => state.StudentData);
const { isLoading: featuresLoading } = useSelector((state) => state.StudentFeatureFlags);
const { isLoading: themeLoading } = useSelector((state) => state.StudentThemes);
const dispatch = useDispatch();
// Theme management is a Basic+ tier feature; the backend gates
// GET /student/account/theme/fetch on require_feature("student.theme_management"),
// so fetching it for a district without the entitlement is a guaranteed 403.
const { isEnabled: themeFeatureEnabled } = useFeatureFlag("student.theme_management", undefined, "student");
useEffect(() => {
dispatch(_studentGetData());
dispatch(fetchStudentDistrictFeatures());
dispatch(fetchStudentOrganization());
}, [dispatch]);
// Fetch the theme only once the district features confirm the entitlement —
// gating the call avoids a guaranteed 403 for sub-Basic plans. The end state is
// identical (no entitlement → default theme); this just skips the doomed request.
useEffect(() => {
if (themeFeatureEnabled) {
dispatch(_fetchStudentTheme());
}
}, [dispatch, themeFeatureEnabled]);
const loading = isLoading || featuresLoading || themeLoading;
return (
<ThemeToggleProvider>
{loading ? (
<>
<SimpleLoading showLoading />
<ThemePresets showTheme={false} />
</>
) : (
<UpgradeDialogProvider userType="student">
<AppLayout>
<Box sx={{ minHeight: "100vh" }}>
<GlobalMaintenanceBanner userType="student" />
<Suspense fallback={<SimpleLoading showLoading />}>
<Outlet />
</Suspense>
</Box>
</AppLayout>
<Copyright />
<IdleChecker idleTime={60 * 2} />
</UpgradeDialogProvider>
)}
</ThemeToggleProvider>
);
}
|