Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import customTheme from "./utils/theme";
import FingerprintJS from "@fingerprintjs/fingerprintjs";
import { checkUserDetails } from "./services/auth/auth";
import teacherAuthRoutes from "./routes/teacherAuth";
import schoolAdminAuth from "./routes/schoolAdminAuth";
import { jwtDecode } from "jwt-decode";

const theme = extendTheme(customTheme);
Expand All @@ -26,9 +27,19 @@ function AppRouter() {
const navigate = useNavigate();
useEffect(() => {
if (token && token !== "not-logged-in") {
const tokenDecoded = jwtDecode(token);
const roles = tokenDecoded?.resource_access?.["hasura-app"]?.roles;
if (authUser && Array.isArray(roles) && roles.includes("teacher")) {
if (
authUser &&
Array.isArray(authUser?.Teachers) &&
authUser?.Teachers.some(
(teacher) => teacher.currentRole === "School_Admin"
)
) {
setRoutes(schoolAdminAuth);
} else if (
authUser &&
Array.isArray(authUser?.Teachers) &&
authUser?.Teachers.some((teacher) => teacher.currentRole === "Teacher")
) {
setRoutes(teacherAuthRoutes);
} else if (authRoutes) {
setRoutes(authRoutes);
Expand Down
134 changes: 134 additions & 0 deletions src/pages/student-admin/SchoolAdmin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { Center, VStack } from "@chakra-ui/react";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { impression } from "../../services/telemetry";
import CustomHeading from "../../components/common/typography/Heading";
import Layout from "../../components/common/layout/layout";
import ClassCard from "../../components/common/cards/ClassCard";
import { getTeacherData } from "../../services/home";
import { checkUserDetails } from "../../services/auth/auth";

export default function SchoolAdminHomepage(props: any) {
const { t } = useTranslation();
const [error, setError] = useState<string | null>(null);
const navigate = useNavigate();
const { authUser } = props;
const [classes, setClasses] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
const fetchTeacherDataForClasses = React.useCallback(async () => {
try {
const result = await checkUserDetails();
if (!result) {
setError("No class details found.");
return;
}

const groupMemberships = result?.data?.GroupMemberships || [];

const classDataArray = await Promise.all(
groupMemberships.map(async (classDetail: any) => {
const payload = {
groupId: classDetail?.Group?.groupId,
schoolUdise: classDetail?.School?.udiseCode,
grade: String(classDetail?.Group?.grade),
medium: classDetail?.Group?.medium,
board: classDetail?.Group?.board,
};

const data = await getTeacherData(payload);

// Create class object
const classObj = {
...data,
subjects: data?.subjectResults || [],
title: `Class ${classDetail?.Group?.grade}`,
groupId: classDetail?.Group?.groupId,
schoolUdise: classDetail?.School?.udiseCode,
grade: String(classDetail?.Group?.grade),
medium: classDetail?.Group?.medium,
board: classDetail?.Group?.board,
};

return classObj;
})
);
setClasses(classDataArray);
} catch (error: any) {
setError(`Error fetching teacher data for classes:${error?.message}`);
} finally {
setLoading(false);
}
}, [authUser]);

useEffect(() => {
fetchTeacherDataForClasses();
}, [authUser]);

useEffect(() => {
impression({
edata: {
type: "SchoolAdminHomepage",
pageid: "SchoolAdminHomepage",
uri: "/schoolAdmin",
query: Object.fromEntries(
new URLSearchParams(location.search).entries()
),
visits: [],
},
});
}, []);

const handleCardClick = (group: any, subject?: any) => {
navigate(
subject
? `/schoolAdmin/${group.board}/${group.schoolUdise}/${group.grade}/${group.medium}/${group.groupId}/${subject}`
: `/schoolAdmin/${group.board}/${group.schoolUdise}/${group.grade}/${group.medium}/${group.groupId}`,
{}
);
};

return (
<Layout
isFooterVisible={false}
_header={{
userInfo: true,
isShowLogOutButton: true,
bgc: "blue40",
}}
loading={loading}
>
{error ? (
<Center h="calc(100vh - 123px)">
<CustomHeading color="red.500" textAlign="center">
{error}
</CustomHeading>
</Center>
) : (
<VStack spacing={4} align={"stretch"} px="4" pb="8">
<CustomHeading
py="4"
textAlign="center"
lineHeight="20px"
fontFamily="Inter"
variant="h2"
fontSize="20px"
fontWeight="500"
title={t("TEACHER_PAGE_VIEW_YOUR_IMPACT")}
color="textPrimary"
/>

{classes?.map((group: any) => (
<ClassCard
key={group.groupId}
title={true}
data={group}
onClick={() => handleCardClick(group)}
subjectClick={(sub) => handleCardClick(group, sub)}
/>
))}
</VStack>
)}
</Layout>
);
}
104 changes: 104 additions & 0 deletions src/pages/student-admin/SchoolAdminDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { Box, Text, VStack } from "@chakra-ui/react";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate, useParams } from "react-router-dom";
import ClassCard from "../../components/common/cards/ClassCard";
import Layout from "../../components/common/layout/layout";
import { getTeacherData } from "../../services/home";
import { impression } from "../../services/telemetry";
import Students from "./SchoolAdminStudent";

export default function SchoolAdminDetails(props: any) {
const { t } = useTranslation();
const [error, setError] = useState<string | null>(null);
const { authUser } = props;
const { board, schoolUdise, grade, medium, groupId, subject } = useParams();
const [classDetails, setClassDetails] = useState<any>({});
const navigate = useNavigate();
const [selectedSubject, setSelectedSubject] = useState<any>(subject);
const [loading, setLoading] = useState<boolean>(true);

useEffect(() => {
const fetchProgramId = async () => {
try {
const payload = {
groupId: groupId,
schoolUdise: schoolUdise,
grade: String(grade),
medium: medium,
board: board,
};
let data = await getTeacherData(payload);
const classObj = {
...data,
subjects: data?.subjectResults || [],
};
setClassDetails(classObj);
} catch (error) {
console.error("Error fetching program data:", error);
setError(t("An unexpected error occurred. Please try again later."));
} finally {
setLoading(false);
}
};

fetchProgramId();
}, [authUser]);

useEffect(() => {
impression({
edata: {
type: "SchoolAdminDetails",
pageid: "SchoolAdminDetails",
uri: "/schoolAdmin",
query: Object.fromEntries(
new URLSearchParams(location.search).entries()
),
visits: [],
},
});
}, []);

return (
<Layout
loading={loading}
isFooterVisible={false}
_header={{
bgc: "blue40",
userInfo: false,
isShowBackButton: true,
headingTitle: `CLASS ${grade}`,
onBack: () => navigate("/schoolAdmin"),
}}
>
<VStack align={"stretch"}>
{error ? (
<Text color="red.500" fontSize="xl" textAlign="center" mt="10">
{error}
</Text>
) : (
<VStack p={4} spacing={4} align={"stretch"}>
<ClassCard
title={false}
data={classDetails}
subjectClick={(e) => setSelectedSubject(e)}
selectedSubject={selectedSubject || "all"}
/>
{/* Table Section */}
<Students
{...{
groupId: groupId || "",
schoolUdise: schoolUdise || "",
grade: String(grade) || "",
medium: medium || "",
board: board || "",
subject:
selectedSubject == "all" ? undefined : selectedSubject || "",
}}
/>
</VStack>
)}
</VStack>
</Layout>
);
}
Loading
Loading