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
commit 11a7265460
392 changed files with 62287 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { queryKeys } from "./keys";
import { communicationService } from "@/services/communication.service";
import type {
DiscussionBoard,
PostCreateRequest,
AnnouncementCreateRequest,
MessageCreateRequest,
} from "@/types/communication";
import type { PaginationParams } from "@/types";
export function useDiscussionBoards(params?: { course_id?: number; batch_id?: number }) {
return useQuery({
queryKey: queryKeys.discussionBoards(params),
queryFn: () => communicationService.listDiscussionBoards(params),
});
}
export function usePosts(boardId: number, params?: PaginationParams) {
return useQuery({
queryKey: queryKeys.posts(boardId, params),
queryFn: () => communicationService.listPosts(boardId, params),
enabled: !!boardId,
});
}
export function useAnnouncements(params?: { course_id?: number; priority?: string }) {
return useQuery({
queryKey: queryKeys.announcements(params),
queryFn: () => communicationService.listAnnouncements(params),
});
}
export function useMessages(params?: { is_read?: boolean } & PaginationParams) {
return useQuery({
queryKey: queryKeys.messages(params),
queryFn: () => communicationService.listMessages(params),
});
}
export function useSentMessages(params?: PaginationParams) {
return useQuery({
queryKey: queryKeys.sentMessages(params),
queryFn: () => communicationService.listSentMessages(params),
});
}
export function useUnreadMessageCount() {
return useQuery({
queryKey: queryKeys.unreadMessages,
queryFn: () => communicationService.getUnreadMessageCount(),
});
}
export function useCreateBoard() {
const qc = useQueryClient();
return useMutation({
mutationFn: (
data: Partial<DiscussionBoard> & Pick<DiscussionBoard, "name" | "course_id">,
) => communicationService.createDiscussionBoard(data),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["discussion-boards"] });
},
});
}
export function useCreatePost() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ boardId, data }: { boardId: number; data: PostCreateRequest }) =>
communicationService.createPost(boardId, data),
onSuccess: (_, { boardId }) => {
qc.invalidateQueries({ queryKey: ["posts", boardId] });
qc.invalidateQueries({ queryKey: ["discussion-boards"] });
},
});
}
export function usePinPost() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ id, body }: { id: number; body?: { pinned?: boolean } }) =>
communicationService.pinPost(id, body),
onSuccess: (post) => {
qc.invalidateQueries({ queryKey: ["posts", post.board_id] });
},
});
}
export function useResolvePost() {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: number) => communicationService.resolvePost(id),
onSuccess: (post) => {
qc.invalidateQueries({ queryKey: ["posts", post.board_id] });
},
});
}
export function useCreateAnnouncement() {
const qc = useQueryClient();
return useMutation({
mutationFn: (data: AnnouncementCreateRequest) => communicationService.createAnnouncement(data),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["announcements"] });
},
});
}
export function usePublishAnnouncement() {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: number) => communicationService.publishAnnouncement(id),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["announcements"] });
},
});
}
export function useSendMessage() {
const qc = useQueryClient();
return useMutation({
mutationFn: (data: MessageCreateRequest) => communicationService.sendMessage(data),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["messages"] });
qc.invalidateQueries({ queryKey: queryKeys.unreadMessages });
},
});
}
export function useDeleteMessage() {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: number) => communicationService.deleteMessage(id),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["messages"] });
qc.invalidateQueries({ queryKey: queryKeys.unreadMessages });
},
});
}