feat(v3): restructure project + add complete frontend

- Restructure: move backend from new_project/ to backend/
- Add full React/TypeScript frontend (37 pages, 17 services, 16 type defs, 11 query hooks)
- Add docs/ with SRS specs, user stories, and workflow documentation
- Update .gitignore for new directory layout

Workflows implemented:
  WF1 User Signup, WF2 Placement Test, WF3 Exam Configuration,
  WF4 General English Exam, WF5 Course Generation,
  WF6 Entity Student Onboarding, AI Course Generation,
  Adaptive Learning Engine UI, White-Label Branding, Score Release

Made-with: Cursor
This commit is contained in:
Yamen Ahmad
2026-04-10 17:26:42 +04:00
parent a3e12f62fa
commit f1c4953a63
731 changed files with 67205 additions and 139 deletions

View File

@@ -0,0 +1,104 @@
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { queryKeys } from "./keys";
import { academicService } from "@/services/academic.service";
import type { PaginationParams } from "@/types";
import type {
AcademicYearCreateRequest,
AcademicTermCreateRequest,
DepartmentCreateRequest,
} from "@/types/academic";
export function useAcademicYears(params?: PaginationParams) {
return useQuery({
queryKey: queryKeys.academicYears.list(params),
queryFn: () => academicService.listAcademicYears(params),
});
}
export function useAcademicYear(id: number) {
return useQuery({
queryKey: queryKeys.academicYears.detail(id),
queryFn: () => academicService.getAcademicYear(id),
enabled: !!id,
});
}
export function useAcademicTerms(yearId?: number) {
return useQuery({
queryKey: queryKeys.academicTerms.list({ year_id: yearId }),
queryFn: () => academicService.listTerms({ year_id: yearId }),
});
}
export function useDepartments(params?: PaginationParams) {
return useQuery({
queryKey: queryKeys.departments.list(params),
queryFn: () => academicService.listDepartments(params),
});
}
export function useCreateAcademicYear() {
const qc = useQueryClient();
return useMutation({
mutationFn: (data: AcademicYearCreateRequest) => academicService.createAcademicYear(data),
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.academicYears.all }),
});
}
export function useUpdateAcademicYear() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: number; data: Partial<AcademicYearCreateRequest> }) =>
academicService.updateAcademicYear(id, data),
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.academicYears.all }),
});
}
export function useDeleteAcademicYear() {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: number) => academicService.deleteAcademicYear(id),
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.academicYears.all }),
});
}
export function useGenerateTerms() {
const qc = useQueryClient();
return useMutation({
mutationFn: (yearId: number) => academicService.generateTerms(yearId),
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.academicTerms.all }),
});
}
export function useCreateAcademicTerm() {
const qc = useQueryClient();
return useMutation({
mutationFn: (data: AcademicTermCreateRequest) => academicService.createTerm(data),
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.academicTerms.all }),
});
}
export function useCreateDepartment() {
const qc = useQueryClient();
return useMutation({
mutationFn: (data: DepartmentCreateRequest) => academicService.createDepartment(data),
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.departments.all }),
});
}
export function useUpdateDepartment() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: number; data: Partial<DepartmentCreateRequest> }) =>
academicService.updateDepartment(id, data),
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.departments.all }),
});
}
export function useDeleteDepartment() {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: number) => academicService.deleteDepartment(id),
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.departments.all }),
});
}