feat(frontend): Phase 2/3 hardening release
Roadmap P0
- Ship /logo.svg fallback and rewire asset references (superseded later by
the project-manager PNG in a separate commit).
Roadmap P1
- Response envelope alignment ({items,total,page,size}) across services
and query hooks.
- Approval/ticket UX updates tied to the new backend rollback semantics.
Roadmap P2
- React.lazy + Vite manualChunks to split vendor-radix/charts/icons/forms
from the main bundle and cut initial JS.
- Fix the 181 tsc errors (PaginationParams class + per-service generics).
- Auto-refresh flow for JWT refresh tokens wired into api-client.ts.
Roadmap P3
- i18n: i18next + language detector, en/ar locales, RTL auto-switch,
LanguageToggle component in RoleLayout and AdminLmsLayout.
- GDPR: PrivacyCenter page for data export and right-to-erasure, backed
by gdpr.service.ts; logout via AuthContext after erasure.
- Human-in-the-loop exam review UI: admin ExamReviewQueue + ExamReviewDetail
pages, useExamReview hooks, exam-review.service.ts.
- AI quality loop: AIPromptEditor (versioning + render preview),
AIFeedbackButtons for students, AIFeedbackTriage admin page, dedicated
services, hooks, and types.
- Dark mode: ThemeProvider + ThemeToggle + chart color tokens.
- Accessibility: DialogDescription on every DialogContent; alert-dialog
and sheet updates.
- Retire dead pages: ExamPage marketing, Index, ProfilePage import.
- Playwright e2e scaffolding: playwright.config.ts + e2e/login.spec.ts
smoke tests, npm scripts test:e2e / test:e2e:install.
Made-with: Cursor
This commit is contained in:
@@ -63,7 +63,7 @@ import { mediaService, type Avatar } from "@/services/media.service";
|
||||
import { examsService } from "@/services/exams.service";
|
||||
import { api } from "@/lib/api-client";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import type { ExamStructureConfig } from "@/types";
|
||||
import type { ExamStructure, ExamStructureConfig } from "@/types";
|
||||
|
||||
type ModuleKey = "reading" | "listening" | "writing" | "speaking" | "level" | "industry";
|
||||
|
||||
@@ -398,7 +398,7 @@ export default function GenerationPage() {
|
||||
|
||||
const createStructureMut = useMutation({
|
||||
mutationFn: (data: { name: string; modules: string[] }) =>
|
||||
examsService.createStructure(data),
|
||||
examsService.createStructure(data as unknown as Partial<ExamStructure>),
|
||||
onSuccess: (created) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["exam-structures"] });
|
||||
setExamStructure(String(created.id));
|
||||
@@ -693,7 +693,7 @@ export default function GenerationPage() {
|
||||
try {
|
||||
const status = await mediaService.getVideoStatus(videoId);
|
||||
if (status.status === "done" || status.status === "completed" || status.video_url) {
|
||||
updatedParts[pp.index] = { ...part, videoUrl: status.video_url || status.url || "" };
|
||||
updatedParts[pp.index] = { ...part, videoUrl: status.video_url || "" };
|
||||
changed = true;
|
||||
toast({ title: "Video ready!", description: "Avatar video has been generated." });
|
||||
} else if (status.status === "error" || status.status === "failed") {
|
||||
@@ -726,7 +726,7 @@ export default function GenerationPage() {
|
||||
totalMarks: st.totalMarks,
|
||||
passages: mod === "reading" ? st.passages.map((p) => ({
|
||||
text: p.text, category: p.category, type: p.type,
|
||||
exercises: p.exercises?.map((ex: Record<string, unknown>) => ({
|
||||
exercises: p.exercises?.map((ex) => ({
|
||||
type: ex.type, prompt: ex.prompt, options: ex.options,
|
||||
correct_answer: ex.correct_answer, explanation: ex.explanation,
|
||||
instructions: ex.instructions, marks: ex.marks || 1,
|
||||
@@ -735,7 +735,7 @@ export default function GenerationPage() {
|
||||
})) : undefined,
|
||||
sections: mod === "listening" ? st.listeningSections.map((s) => ({
|
||||
type: s.type, context: s.context, audioUrl: s.audioUrl,
|
||||
exercises: s.exercises?.map((ex: Record<string, unknown>) => ({
|
||||
exercises: s.exercises?.map((ex) => ({
|
||||
type: ex.type, prompt: ex.prompt, options: ex.options,
|
||||
correct_answer: ex.correct_answer, explanation: ex.explanation,
|
||||
instructions: ex.instructions, marks: ex.marks || 1,
|
||||
|
||||
Reference in New Issue
Block a user