diff --git a/src/components/academic/departments/create-department.tsx b/src/components/academic/departments/create-department.tsx
index 70c174f..6f98318 100644
--- a/src/components/academic/departments/create-department.tsx
+++ b/src/components/academic/departments/create-department.tsx
@@ -22,9 +22,10 @@ const CreateDepartment = () => {
name: "",
school: "",
established: "",
+ head: "",
});
- // Create department
+ // Create department
const handleCreateSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
@@ -41,6 +42,7 @@ const CreateDepartment = () => {
name: "",
school: "",
established: "",
+ head: "",
});
refreshDepartment();
setIsCreateDialogOpen(false);
@@ -90,6 +92,16 @@ const CreateDepartment = () => {
placeholder="Enter school name"
/>
+
+
+ InputHandler(e, setCreateDepartment)}
+ name="head"
+ placeholder="Enter Head of Department name"
+ />
+
{
+const EditDepartment = ({ departmentInfo }: EditDepartmentProps) => {
const refreshDepartment = useRecoilRefresher_UNSTABLE(department);
const [editingDepartment, setEditingDepartment] =
@@ -97,6 +97,16 @@ const EditDepartment = ({ departmentInfo }: EditDepartmentData) => {
placeholder="Enter school name"
/>
+
+
+ InputHandler(e, setEditingDepartment)}
+ name="school"
+ placeholder="Enter Head of Department Name"
+ />
+
{
Department Head:{" "}
- {/* {dept.head} */}
+ {dept.head}
@@ -106,7 +106,9 @@ const AcademicDepartmentTab = () => {
))
) : (
-
No department available to show
+
+ No department available to show
+
)}
>
diff --git a/src/components/academic/semester/create-semster.tsx b/src/components/academic/semester/create-semster.tsx
index 01b78b7..f44e46f 100644
--- a/src/components/academic/semester/create-semster.tsx
+++ b/src/components/academic/semester/create-semster.tsx
@@ -1,150 +1,148 @@
-// import UseModel from "@/components/models/useModel";
-// import { Button } from "@/components/ui/button";
-// import { Input } from "@/components/ui/input";
-// import { Label } from "@/components/ui/label";
-// import {
-// Select,
-// SelectContent,
-// SelectItem,
-// SelectTrigger,
-// SelectValue,
-// } from "@/components/ui/select";
-// import { InputHandler, SelectHandler } from "@/lib/utils";
-// import axios from "axios";
-// import { Plus } from "lucide-react";
-// import { useState } from "react";
-// import { toast } from "sonner";
-// // import type { SemesterData } from "@/types";
-// import { useRecoilRefresher_UNSTABLE } from "recoil";
-// import { semester } from "@/store/atoms/academics/semester";
+import UseModel from "@/components/models/useModel";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+import { InputHandler, SelectHandler } from "@/lib/utils";
+import axios from "axios";
+import { Plus } from "lucide-react";
+import { useState } from "react";
+import { toast } from "sonner";
+import { useRecoilRefresher_UNSTABLE } from "recoil";
+import { semester } from "@/store/atoms/academics/semester";
+import type { SemesterData } from "@/types";
-// const base_api = import.meta.env.VITE_SERVER_BASE_URL;
+const base_api = import.meta.env.VITE_SERVER_BASE_URL;
const CreateSemester = () => {
-// const refreshSemester = useRecoilRefresher_UNSTABLE(semester);
+ const refreshSemester = useRecoilRefresher_UNSTABLE(semester);
-// const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
-// const [isLoading, setIsLoading] = useState(false);
+ const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
- // const [createSemester, setCreateSemester] = useState({
- // semester: "",
- // courses: [""],
- // enddate: "",
- // startdate: "",
- // status: "",
- // });
+ const [createSemester, setCreateSemester] = useState({
+ semester: "",
+ courses: "",
+ enddate: "",
+ startdate: "",
+ status: "",
+ });
// Create department submit
-// const handleCreateSubmit = async (e: React.FormEvent) => {
-// e.preventDefault();
-// setIsLoading(true);
+ const handleCreateSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setIsLoading(true);
-// try {
-// const response = await axios.post(
-// `${base_api}/api/v1/create-program`,
-// createSemester,
+ try {
+ const response = await axios.post(
+ `${base_api}/api/v1/create-semester`,
+ createSemester,
-// { withCredentials: true }
-// );
-// if (response.status === 201) {
-// setCreateSemester({
-// semester: "",
-// courses: [],
-// enddate: "",
-// startdate: "",
-// status: "",
-// });
-// toast.success("program created successfully");
-// setIsLoading(false);
-// refreshSemester();
-// setIsCreateDialogOpen(false);
-// }
-// } catch (error: any) {
-// console.error(error?.message);
-// toast.error("Failed to create program");
-// setIsLoading(false);
-// setIsCreateDialogOpen(false);
-// }
-// };
+ { withCredentials: true }
+ );
+ if (response.status === 201) {
+ setCreateSemester({
+ semester: "",
+ courses: "",
+ enddate: "",
+ startdate: "",
+ status: "",
+ });
+ toast.success("program created successfully");
+ setIsLoading(false);
+ refreshSemester();
+ setIsCreateDialogOpen(false);
+ }
+ } catch (error: any) {
+ console.error(error?.message);
+ toast.error("Failed to create program");
+ setIsLoading(false);
+ setIsCreateDialogOpen(false);
+ }
+ };
return (
- //
- //
- // Add new
- //
- // }
- // >
- //
- //
- // InputHandler(e, setCreateSemester)}
- // placeholder="Enter semester name"
- // />
- //
- //
- //
- // InputHandler(e, setCreateSemester)}
- // placeholder="Enter semester name"
- // />
- //
+
+
+ Add new
+
+ }
+ >
+
+
+ InputHandler(e, setCreateSemester)}
+ placeholder="Enter semester name"
+ />
+
+
+
+ InputHandler(e, setCreateSemester)}
+ placeholder="Enter semester name"
+ />
+
- //
- //
- // InputHandler(e, setCreateSemester)}
- // />
- //
- //
- //
- // InputHandler(e, setCreateSemester)}
- // />
- //
- //
- //
- //
- //
- //
-
- not Implemented yet
+
+
+ InputHandler(e, setCreateSemester)}
+ />
+
+
+
+ InputHandler(e, setCreateSemester)}
+ />
+
+
+
+
+
+
);
};
diff --git a/src/components/academic/semester/edit-semester.tsx b/src/components/academic/semester/edit-semester.tsx
index e69de29..5cde540 100644
--- a/src/components/academic/semester/edit-semester.tsx
+++ b/src/components/academic/semester/edit-semester.tsx
@@ -0,0 +1,154 @@
+import UseModel from "@/components/models/useModel";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+import { FormateDate, InputHandler, SelectHandler } from "@/lib/utils";
+import axios from "axios";
+import { Edit } from "lucide-react";
+import { useState } from "react";
+import { toast } from "sonner";
+import type { EditSemesterProps, SemesterData } from "@/types";
+import { useRecoilRefresher_UNSTABLE } from "recoil";
+import { semester } from "@/store/atoms/academics/semester";
+
+const base_api = import.meta.env.VITE_SERVER_BASE_URL;
+
+const EditSemester = ({ semesterInfo }: EditSemesterProps) => {
+ const refreshSemester = useRecoilRefresher_UNSTABLE(semester);
+
+ const [editingSemester, setEditingSemester] = useState(
+ null
+ );
+ const [isUpdateDialogOpen, setIsUpdateDialogOpen] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+
+ // Update course submit
+ const handleUpdateSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!editingSemester?.id) return;
+ setIsLoading(true);
+
+ console.log(editingSemester);
+
+ try {
+ const response = await axios.put(
+ `${base_api}/api/v1/update-semester/${editingSemester.id}`,
+ editingSemester,
+ { withCredentials: true }
+ );
+ if (response.status === 201) {
+ toast.success("program updated successfully");
+ refreshSemester();
+ setIsLoading(false);
+ setIsUpdateDialogOpen(false);
+ }
+ } catch (error: any) {
+ console.error(error?.message);
+ toast.error("Failed to update program");
+ setIsUpdateDialogOpen(false);
+ setIsLoading(false);
+ }
+ };
+
+ // Handle edit button click
+ const handleEditClick = (semesterInfo: SemesterData) => {
+ setEditingSemester({ ...semesterInfo });
+ setIsUpdateDialogOpen(true);
+ };
+
+ return (
+ handleEditClick(semesterInfo)}
+ >
+
+ Update
+
+ }
+ >
+ {editingSemester && (
+ <>
+
+
+ InputHandler(e, setEditingSemester)}
+ placeholder="Enter semester name"
+ />
+
+
+
+ InputHandler(e, setEditingSemester)}
+ placeholder="Enter semester name"
+ />
+
+
+
+
+ InputHandler(e, setEditingSemester)}
+ />
+
+
+
+ InputHandler(e, setEditingSemester)}
+ />
+
+
+
+
+
+ >
+ )}
+
+ );
+};
+
+export default EditSemester;
diff --git a/src/components/academic/semester/index.tsx b/src/components/academic/semester/index.tsx
index 7bbaa45..a61606b 100644
--- a/src/components/academic/semester/index.tsx
+++ b/src/components/academic/semester/index.tsx
@@ -4,16 +4,60 @@ import { Card, CardContent } from "@/components/ui/card";
import { FormateDate } from "@/lib/utils";
import { useSemesterData } from "@/store/hooks/academics/use-semester-data";
import type { SemesterData } from "@/types";
-import { Edit } from "lucide-react";
+import { Trash } from "lucide-react";
import CreateSemester from "./create-semster";
+import EditSemester from "./edit-semester";
+import { ConfirmDialog } from "@/components/confirm-dialog";
+import { useState } from "react";
+import axios from "axios";
+import { toast } from "sonner";
+import { useRecoilRefresher_UNSTABLE } from "recoil";
+import { semester } from "@/store/atoms/academics/semester";
+import { Skeleton } from "@/components/ui/skeleton";
+
+const base_api = import.meta.env.VITE_SERVER_BASE_URL;
const AcademicSemesterTab = () => {
- const { semesterInfo, loading } = useSemesterData();
+ const { semesterInfo, loading, error } = useSemesterData();
+ const refreshProgram = useRecoilRefresher_UNSTABLE(semester);
+ const [isLoading, setIsLoading] = useState(false);
+
+ // handle Delete
- if (loading) {
- return loading...
;
+ async function handleDelete(semester: SemesterData) {
+ try {
+ const response = await axios.delete(
+ `${base_api}/api/v1/delete-semester/${semester?.id}`,
+ {
+ withCredentials: true,
+ }
+ );
+
+ if (response.status === 201) {
+ toast.success("Program deleted !!");
+ setIsLoading(false);
+ refreshProgram();
+ }
+ } catch (error) {
+ console.log(error);
+ setIsLoading(false);
+ }
}
+ if (loading)
+ return (
+
+
+
+ );
+
+ if (error)
+ return (
+
+ Error loading courses data.
+
+ );
+
const semesterData: SemesterData[] = semesterInfo?.Semesters;
return (
@@ -24,56 +68,74 @@ const AcademicSemesterTab = () => {
- {semesterData?.map((semester, index) => (
-
-
-
-
-
-
{semester.semester}
-
- {semester.status}
-
-
-
-
-
Start Date:
- {FormateDate(semester.startdate)}
+ {semesterData?.length > 0 ? (
+ semesterData.map((semester, index) => (
+
+
+
+
+
+
{semester.semester}
+
+ {semester.status}
+
-
-
End Date:
- {FormateDate(semester.enddate)}
+
+
+ Start Date:
+ {FormateDate(semester.startdate)}
+
+
+ End Date:
+ {FormateDate(semester.enddate)}
+
+
+ Courses:
+ {semester.courses}
+
+
+
+
+
+ {/* delete program */}
- Courses:
- {semester.courses}
+ handleDelete(semester)}
+ destructive
+ trigger={
+
+ }
+ />
-
-
- {semester.status === "Planning" && (
-
- )}
-
-
-
-
-
- ))}
+
+
+ ))
+ ) : (
+
+ No semester available to show
+
+ )}
>
);
diff --git a/src/components/dashboard-welcome.tsx b/src/components/dashboard-welcome.tsx
index c2f4e4d..49d7304 100644
--- a/src/components/dashboard-welcome.tsx
+++ b/src/components/dashboard-welcome.tsx
@@ -1,21 +1,14 @@
import { useAdminData } from "@/store/hooks/useAdminData";
import { AlertCircle, Verified } from "lucide-react";
-import { useEffect } from "react";
-import { Link, useNavigate } from "react-router-dom";
+
+import { Link } from "react-router-dom";
import { Skeleton } from "./ui/skeleton";
const DashboardWelcome = () => {
const { adminInfo, loading, error } = useAdminData();
- const navigate = useNavigate();
const userInfo = adminInfo?.isUserExist;
- useEffect(() => {
- if (!loading && !userInfo) {
- navigate("/auth/user-email");
- }
- }, [loading, userInfo, navigate]);
-
if (loading)
return (
diff --git a/src/components/otp-step.tsx b/src/components/otp-step.tsx
index 79163f4..758f7ab 100644
--- a/src/components/otp-step.tsx
+++ b/src/components/otp-step.tsx
@@ -6,14 +6,14 @@ import {
InputOTPSeparator,
InputOTPSlot,
} from "@/components/ui/input-otp";
-
import { REGEXP_ONLY_DIGITS } from "input-otp";
-
import { Label } from "@/components/ui/label";
import axios from "axios";
import { useState } from "react";
import { useNavigate } from "react-router";
import { toast } from "sonner";
+import { useRecoilRefresher_UNSTABLE } from "recoil";
+import { admin } from "@/store/atoms/admin";
type OtpStepProps = {
apiEndpoint: string;
@@ -30,6 +30,7 @@ export const OtpStep = ({
subtitle = "We've sent OTP to your email",
inputCount = 6,
}: OtpStepProps) => {
+ const refreshAdminData = useRecoilRefresher_UNSTABLE(admin);
const [otp, setOtp] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState
(null);
@@ -56,13 +57,14 @@ export const OtpStep = ({
if (response.status === 200) {
toast.success("OTP verified!");
setOtp("");
+ await refreshAdminData();
navigate(redirectTo);
return;
}
} catch (err: any) {
if (err?.response?.status === 403) {
toast.error(err.response?.data?.message || "OTP Expired");
- navigate("/auth/user-email")
+ navigate("/auth/user-email");
}
const msg = err.response?.data?.message || "OTP verification failed";
setError(msg);
diff --git a/src/components/route-protection/auth-protected-route.tsx b/src/components/route-protection/auth-protected-route.tsx
new file mode 100644
index 0000000..94f4cda
--- /dev/null
+++ b/src/components/route-protection/auth-protected-route.tsx
@@ -0,0 +1,15 @@
+// auth-protected-route.tsx
+import React from "react";
+import { ProtectedRoute } from "@/components/route-protection/protected-route";
+
+interface AuthProtectedRouteProps {
+ children: React.ReactNode;
+}
+
+export const AuthProtectedRoute: React.FC = ({
+ children,
+}) => {
+ return (
+ {children}
+ );
+};
diff --git a/src/components/route-protection/dashboard-protected-route.tsx b/src/components/route-protection/dashboard-protected-route.tsx
new file mode 100644
index 0000000..a3115ac
--- /dev/null
+++ b/src/components/route-protection/dashboard-protected-route.tsx
@@ -0,0 +1,12 @@
+import React from "react";
+import { ProtectedRoute } from "@/components/route-protection/protected-route";
+
+interface DashboardProtectedRouteProps {
+ children: React.ReactNode;
+}
+
+export const DashboardProtectedRoute: React.FC<
+ DashboardProtectedRouteProps
+> = ({ children }) => {
+ return {children};
+};
diff --git a/src/components/route-protection/protected-route.tsx b/src/components/route-protection/protected-route.tsx
new file mode 100644
index 0000000..b3f9daa
--- /dev/null
+++ b/src/components/route-protection/protected-route.tsx
@@ -0,0 +1,35 @@
+import React from "react";
+import { useProtectedRoute } from "@/hooks/use-protected-route";
+import { BookOpen } from "lucide-react";
+
+interface ProtectedRouteProps {
+ children: React.ReactNode;
+ requireVerification?: boolean;
+}
+
+export const ProtectedRoute: React.FC = ({
+ children,
+ requireVerification = true,
+}) => {
+ const { loading, shouldRender } = useProtectedRoute(requireVerification);
+
+ if (loading) {
+ return (
+
+ );
+ }
+
+ if (!shouldRender) {
+ return (
+
+
Please verify your account
+
+ );
+ }
+
+ return <>{children}>;
+};
diff --git a/src/hooks/use-protected-route.ts b/src/hooks/use-protected-route.ts
new file mode 100644
index 0000000..42c5428
--- /dev/null
+++ b/src/hooks/use-protected-route.ts
@@ -0,0 +1,45 @@
+import { useNavigate } from "react-router";
+import { useRouteGuards } from "./use-route-guard";
+import { useEffect } from "react";
+import { toast } from "sonner";
+
+export const useProtectedRoute = (requiredVerification = true) => {
+ const { loading, isUserExist, isVerified } = useRouteGuards();
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ if (loading) return;
+
+ // If user not verified
+ if (requiredVerification) {
+ // user not created account yet
+ if (!isUserExist) {
+ navigate("/auth/sign-up", { replace: true });
+ toast.warning("please create account to get access in My-Uni");
+ return;
+ }
+
+ // user not verified account yet
+ if (isUserExist && !isVerified) {
+ navigate("/auth/user-email", { replace: true });
+ toast.warning("please verify your account");
+ return;
+ }
+ } else {
+ if (isUserExist && isVerified) {
+ navigate("/", { replace: true });
+ toast.success("welcome to the board");
+ return;
+ }
+ }
+ }, [loading, isUserExist, isVerified, requiredVerification, navigate]);
+
+ return {
+ loading,
+ isUserExist,
+ isVerified,
+ shouldRender: requiredVerification
+ ? isUserExist && isVerified
+ : !isUserExist || !isVerified,
+ };
+};
diff --git a/src/hooks/use-route-guard.ts b/src/hooks/use-route-guard.ts
new file mode 100644
index 0000000..b27df2f
--- /dev/null
+++ b/src/hooks/use-route-guard.ts
@@ -0,0 +1,35 @@
+import { useNavigate } from "react-router-dom";
+import { useAdminData } from "@/store/hooks/useAdminData";
+
+export const useRouteGuards = () => {
+ const { adminInfo, loading } = useAdminData();
+ const navigate = useNavigate();
+
+ const userInfo = adminInfo?.isUserExist;
+
+ const redirectToVerification = () => {
+ if (loading) return;
+
+ if (!loading && !userInfo) {
+ navigate("/auth/sign-up");
+ } else if (!loading && userInfo && !userInfo.isVerified) {
+ navigate("/auth/user-email");
+ }
+ };
+
+ const redirectToDashboard = () => {
+ if (loading) return;
+ if (!loading && userInfo && userInfo.isVerified) {
+ navigate("/");
+ }
+ };
+
+ return {
+ userInfo,
+ loading,
+ isUserExist: !!userInfo,
+ isVerified: userInfo?.isVerified || false,
+ redirectToVerification,
+ redirectToDashboard,
+ };
+};
diff --git a/src/pages/auth/forgot-password/verify-otp.tsx b/src/pages/auth/forgot-password/verify-otp.tsx
index 768ea59..79397cb 100644
--- a/src/pages/auth/forgot-password/verify-otp.tsx
+++ b/src/pages/auth/forgot-password/verify-otp.tsx
@@ -7,7 +7,8 @@ export default function VerifyOtp() {
);
}
diff --git a/src/pages/auth/sign-in.tsx b/src/pages/auth/sign-in.tsx
index c9bcf01..daa87c4 100644
--- a/src/pages/auth/sign-in.tsx
+++ b/src/pages/auth/sign-in.tsx
@@ -12,6 +12,8 @@ import { useState } from "react";
import { Link } from "react-router-dom";
import { toast } from "sonner";
import { useNavigate } from "react-router";
+import { useRecoilRefresher_UNSTABLE } from "recoil";
+import { admin } from "@/store/atoms/admin";
interface UserData {
email?: string;
@@ -21,6 +23,8 @@ interface UserData {
const server_base_api = import.meta.env.VITE_SERVER_BASE_URL;
export default function SignIn() {
+ const refreshAdminData = useRecoilRefresher_UNSTABLE(admin);
+
const navigate = useNavigate();
const [showPassword, setShowPassword] = useState(true);
@@ -45,14 +49,15 @@ export default function SignIn() {
withCredentials: true,
}
);
- if (response.status === 200) {
+ if (response.status === 200) {
setIsLoading(false);
setUserData({
email: "",
password: "",
});
toast.success("credentials matched!!");
- navigate("/");
+ await refreshAdminData();
+ navigate("/auth/user-email");
return;
}
} catch (error: any) {
@@ -122,7 +127,7 @@ export default function SignIn() {
value={userData?.password}
onChange={(e) => InputHandler(e, setUserData)}
type={showPassword ? "text" : "password"}
- placeholder="jhondow@1234"
+ placeholder="johndow@1234"
/>
);
}
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index e90e8ff..8e8f97f 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -16,25 +16,44 @@ import Setting from "@/pages/dashboard/setting";
import Users from "@/pages/dashboard/users";
import NotFound from "@/pages/not-found";
import { Routes, Route } from "react-router-dom";
+import { DashboardProtectedRoute } from "@/components/route-protection/dashboard-protected-route";
+import { AuthProtectedRoute } from "@/components/route-protection/auth-protected-route";
const Paths = () => {
return (
}>
- } />
- } />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
} />
- {/* forgot-password */}
} />
} />
-
- {/* verify-user */}
} />
} />
- {/* dashboard */}
- }>
+
+
+
+ }
+ >
} />
} />
} />
@@ -43,6 +62,8 @@ const Paths = () => {
} />
} />
+
+ {/* Not Found */}
} />
);
diff --git a/src/store/selectors/admin.ts b/src/store/selectors/admin.ts
index 3305693..4e4c4cd 100644
--- a/src/store/selectors/admin.ts
+++ b/src/store/selectors/admin.ts
@@ -1,6 +1,6 @@
+// adminSelector.ts
import axios from "axios";
import { selector } from "recoil";
-import { toast } from "sonner";
const base_api = import.meta.env.VITE_SERVER_BASE_URL;
@@ -8,16 +8,32 @@ export const adminSelector = selector({
key: "AdminSelector",
get: async () => {
try {
+ console.log(
+ "adminSelector - Making request to:",
+ `${base_api}/api/v1/about-me`
+ );
+
const response = await axios.get(`${base_api}/api/v1/about-me`, {
withCredentials: true,
});
+
+ console.log("adminSelector - Response:", response.data);
return response.data;
} catch (error: any) {
+ console.log(
+ "adminSelector - Error:",
+ error.response?.status,
+ error.response?.data
+ );
+
if (error?.response?.status === 401) {
- toast.error("sign-in again");
+ return {
+ message: "User not authenticated",
+ isUserExist: null,
+ };
}
+
console.error("Admin fetch failed:", error.message);
- console.error("Admin fetch failed:", error);
throw error;
}
},
diff --git a/src/types/index.d.ts b/src/types/index.d.ts
index 8402804..eedcaa2 100644
--- a/src/types/index.d.ts
+++ b/src/types/index.d.ts
@@ -42,23 +42,24 @@ export interface EditProgramProps {
export interface DepartmentData {
id?: string;
name: string;
+ head: string;
school: string;
established: string;
}
-export interface EditDepartmentData {
+export interface EditDepartmentProps {
departmentInfo: DepartmentData;
}
export interface SemesterData {
id?: string;
semester: string;
- courses: number[];
+ courses: string;
startdate: string;
enddate: string;
status: string;
}
-export interface EditSemesterData {
- semester: SemesterData;
+export interface EditSemesterProps {
+ semesterInfo: SemesterData;
}