feat: add new pages and components for Cahier de texte and Notes & Ex…#30
Conversation
…amens modules - Implemented Cahier de texte module with tabs for Programme réalisé, Devoirs donnés, Suivi des chapitres, Documents pédagogiques, and E-learning. - Implemented Notes & Examens module with tabs for Saisie des notes, Bulletins, Moyenne auto, Classement, Délibération, Gestion des examens, Export PDF, and Signature numérique. - Each tab currently displays a maintenance placeholder indicating future functionality. - Updated App routing to include new pages for Cahier de texte and Notes & Examens.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThis PR adds two protected dashboard features: Notes & Examens (tabbed page with a full note-entry CRUD tab and several maintenance tabs) and Cahier de Texte (tabbed curriculum pages in maintenance). Routes and sidebar entries are wired for both features. ChangesNotes & Examens and Cahier de Texte
Sequence DiagramsequenceDiagram
participant User
participant Sidebar
participant NotesExamensPage
participant SaisieNotesTab
participant ReactQuery as React Query
participant API
User->>Sidebar: click "Notes & Examens"
Sidebar->>NotesExamensPage: navigate to /notes-examens
NotesExamensPage->>NotesExamensPage: set activeTab = "saisie-notes"
NotesExamensPage->>SaisieNotesTab: render tab component
SaisieNotesTab->>ReactQuery: useQuery(classes)
SaisieNotesTab->>ReactQuery: useQuery(notes for filtered class)
ReactQuery->>API: GET /classes, GET /notes?classeId
API-->>ReactQuery: class list, notes data
ReactQuery-->>SaisieNotesTab: populate table & filter
User->>SaisieNotesTab: click "Saisir une note"
SaisieNotesTab->>SaisieNotesTab: open modal, load students/subjects
User->>SaisieNotesTab: fill form, upload sheet, submit
SaisieNotesTab->>ReactQuery: useMutation(POST/PUT /notes)
ReactQuery->>API: POST/PUT with FormData (grades, comment, file)
API-->>ReactQuery: created/updated note
ReactQuery->>ReactQuery: invalidate notes query
ReactQuery-->>SaisieNotesTab: refresh table, show toast, close modal
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/src/components/notes/SaisieNotesTab.tsx`:
- Around line 176-179: The invalidation uses stale component state
(deleteTarget?.classeId) which may be cleared before the mutation completes;
change the mutation handlers (the onSuccess/onSettled for the delete mutation in
SaisieNotesTab) to use the mutation's variables/response instead of deleteTarget
state (e.g., use the second onSuccess argument "variables" or the onSettled args
to read variables.classeId) when calling
queryClient.invalidateQueries(["classe-notes", ...]); update the other
occurrence at the block around lines 614-622 the same way so invalidation always
uses the mutation's classeId rather than deleteTarget.
- Around line 198-204: openEdit pre-fills matiereId from the optional relation
note.matiere, which can be undefined and yields an empty string that users
cannot change in edit mode; update the setForm call in openEdit to use the
persisted foreign key (note.matiereId) as the primary source (e.g., matiereId:
note.matiereId ?? note.matiere?.id ?? ""), so the edit form always receives a
valid id when available.
In `@apps/web/src/pages/NotesExamensPage.tsx`:
- Around line 91-110: Tabs currently set aria-controls but buttons lack explicit
id and the panel (role="tabpanel" with id={`tabpanel-${activeTab}`}) lacks
aria-labelledby; add a deterministic id on each tab button (e.g., `tab-${id}`
inside the button rendered in the map) and set the panel's aria-labelledby to
that tab id (aria-labelledby={`tab-${activeTab}`}) so the TABS mapping,
activeTab state, the button render and the panel div (role="tabpanel") are
reciprocally linked for screen readers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e010dc2d-4b0a-4a75-8ff5-9e00791529a8
📒 Files selected for processing (19)
apps/web/src/App.tsxapps/web/src/components/Sidebar.tsxapps/web/src/components/cahierTexte/DevoirsDonnesTab.tsxapps/web/src/components/cahierTexte/DocumentsPedagogiquesTab.tsxapps/web/src/components/cahierTexte/ELearningTab.tsxapps/web/src/components/cahierTexte/MaintenancePlaceholder.tsxapps/web/src/components/cahierTexte/ProgrammeRealiseTab.tsxapps/web/src/components/cahierTexte/SuiviChapitresTab.tsxapps/web/src/components/notes/BulletinsTab.tsxapps/web/src/components/notes/ClassementTab.tsxapps/web/src/components/notes/DeliberationTab.tsxapps/web/src/components/notes/ExportPdfTab.tsxapps/web/src/components/notes/GestionExamensTab.tsxapps/web/src/components/notes/MaintenancePlaceholder.tsxapps/web/src/components/notes/MoyenneAutoTab.tsxapps/web/src/components/notes/SaisieNotesTab.tsxapps/web/src/components/notes/SignatureNumeriqueTab.tsxapps/web/src/pages/CahierTextePage.tsxapps/web/src/pages/NotesExamensPage.tsx
| onSuccess: () => { | ||
| queryClient.invalidateQueries({ | ||
| queryKey: ["classe-notes", deleteTarget?.classeId], | ||
| }); |
There was a problem hiding this comment.
Invalidate delete cache with mutation variables, not deleteTarget state.
At Lines 177-179, invalidation uses deleteTarget?.classeId. deleteTarget can be cleared via cancel/backdrop flow before the request resolves, which can produce ["classe-notes", undefined] and leave stale notes in view.
Suggested fix
- onSuccess: () => {
+ onSuccess: (_, variables) => {
queryClient.invalidateQueries({
- queryKey: ["classe-notes", deleteTarget?.classeId],
+ queryKey: ["classe-notes", variables.classeId],
});
toast.success("Note supprimée.");
setDeleteTarget(null);
},Also applies to: 614-622
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/components/notes/SaisieNotesTab.tsx` around lines 176 - 179, The
invalidation uses stale component state (deleteTarget?.classeId) which may be
cleared before the mutation completes; change the mutation handlers (the
onSuccess/onSettled for the delete mutation in SaisieNotesTab) to use the
mutation's variables/response instead of deleteTarget state (e.g., use the
second onSuccess argument "variables" or the onSettled args to read
variables.classeId) when calling queryClient.invalidateQueries(["classe-notes",
...]); update the other occurrence at the block around lines 614-622 the same
way so invalidation always uses the mutation's classeId rather than
deleteTarget.
…th ARIA attributes
…amens modules
Summary by CodeRabbit