Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Adds admin-facing management for students/semesters/classes/records plus a new polls feature (QR-based poll responding + results), backed by Drizzle schema/migrations and updated dashboard navigation/layout.
Changes:
- Introduces new Drizzle schema entities:
class,student_class, and poll-related tables; wires rooms/polls to optional semester/class. - Adds new admin pages/filters/tables for Semesters, Classes, Students, Records (+ CSV export), and Polls (list/detail/edit).
- Updates sidebar + protected layout with a new site header, and adds/refreshes multiple shadcn-style UI primitives.
Reviewed changes
Copilot reviewed 92 out of 93 changed files in this pull request and generated 20 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/attendance/take-attendance.spec.ts | Cleans up new tables during test teardown. |
| tests/attendance/create-room.spec.ts | Cleans up new tables during test teardown. |
| src/lib/schema.ts | Adds class/student_class + poll schema and relations; adds room.classId and attendant.email. |
| src/lib/poll.constants.ts | Adds poll cookie/key constants. |
| src/hooks/usePollUrl.tsx | Client hook to generate/refresh poll QR URLs via SWR. |
| src/hooks/usePollResults.tsx | Client hook to fetch/refresh poll results via SWR. |
| src/config/config.tsx | Adds Poll config + expands sidebar navigation items. |
| src/components/ui/toast.tsx | Minor variant styling/formatting tweaks. |
| src/components/ui/textarea.tsx | Adds Textarea primitive. |
| src/components/ui/table.tsx | Adds Table primitives. |
| src/components/ui/separator.tsx | Refactors Separator primitive. |
| src/components/ui/select.tsx | Adds Select primitive. |
| src/components/ui/pagination.tsx | Adjusts PaginationLink prop typing. |
| src/components/ui/label.tsx | Refactors Label primitive. |
| src/components/ui/input.tsx | Refactors Input primitive styling/structure. |
| src/components/ui/input-group.tsx | Adds InputGroup composite component. |
| src/components/ui/field.tsx | Adds Field layout primitives and error rendering. |
| src/components/ui/combobox.tsx | Adds Combobox primitives based on Base UI. |
| src/components/ui/checkbox.tsx | Adds Checkbox primitive. |
| src/components/ui/card.tsx | Refactors Card primitive structure and variants. |
| src/components/ui/button.tsx | Refactors Button primitive and variants. |
| src/components/ui/badge.tsx | Adds Badge primitive. |
| src/components/ui/alert-dialog.tsx | Adds AlertDialog primitive wrappers. |
| src/components/polls/PollQRCodePanel.tsx | Poll QR panel with countdown + manual nonce refresh. |
| src/components/pages/students/StudentTable.tsx | Students table with class badges + edit/delete actions. |
| src/components/pages/students/StudentFilters.tsx | Semester/class filtering UI for students page. |
| src/components/pages/semesters/SemesterTable.tsx | Semesters table with edit/delete + active toggle. |
| src/components/pages/semesters/CreateSemesterDialog.tsx | Dialog to create semesters via server action. |
| src/components/pages/records/RecordsTable.tsx | Attendance records table showing student, room, semester, classes. |
| src/components/pages/records/RecordsFilters.tsx | Semester/class filtering UI for records page. |
| src/components/pages/records/ExportButton.tsx | Client-side button to download CSV export with filters. |
| src/components/pages/polls/poll.types.ts | Zod schemas + shared types for poll create/response/results. |
| src/components/pages/polls/PollResultsView.tsx | Admin poll results visualization. |
| src/components/pages/polls/PollList.tsx | Admin poll listing cards with open/close + delete. |
| src/components/pages/polls/PollDetailView.tsx | Poll detail layout (QR + results). |
| src/components/pages/polls/PollActions.tsx | Poll open/close + edit/delete controls. |
| src/components/pages/poll-respond/PollResponseSuccess.tsx | Success screen after poll submission. |
| src/components/pages/poll-respond/PollResponseResults.tsx | Public results view after responding. |
| src/components/pages/poll-respond/PollResponseForm.tsx | Public poll response form rendering per question type. |
| src/components/pages/createRoom.type.ts | Extends room form schema with optional semester/class. |
| src/components/pages/classes/CreateClassDialog.tsx | Dialog to create classes tied to a semester. |
| src/components/pages/classes/ClassTable.tsx | Classes table with edit/delete and semester selection. |
| src/components/pages/attendance/RoomActions.tsx | Passes semester/class context into UpdateRoomDialog. |
| src/components/pages/attendance/AttendanceList.tsx | Displays semester/class on room cards; passes to UpdateRoomDialog. |
| src/components/pages/attendance/AttendanceDetailView.tsx | Displays semester/class on detail view; passes to RoomActions. |
| src/components/pages/UpdateRoomDialog.tsx | Adds semester/class selectors when updating a room. |
| src/components/pages/CreateRoomDialog.tsx | Adds semester/class selectors when creating a room. |
| src/components/header/site-header.tsx | New top header (sidebar trigger + breadcrumb + user). |
| src/components/header/sidebar.tsx | Makes sidebar client-side and highlights active route. |
| src/components/example.tsx | Adds example wrapper/content components. |
| src/app/(public)/poll/[id]/respond/page.tsx | Public poll respond page (nonce-based) with results after submit. |
| src/app/(internal)/(protected)/actions.tsx | Adds admin semester/class fetchers; persists room semester/class. |
| src/app/(internal)/(protected)/(sidebar)/students/page.tsx | Students admin page with pagination and filters. |
| src/app/(internal)/(protected)/(sidebar)/semesters/page.tsx | Semesters admin page with pagination. |
| src/app/(internal)/(protected)/(sidebar)/semesters/actions.tsx | Semester CRUD server actions. |
| src/app/(internal)/(protected)/(sidebar)/semesters/[id]/page.tsx | Semester detail page listing classes in that semester. |
| src/app/(internal)/(protected)/(sidebar)/semesters/[id]/actions.tsx | Semester detail + classes CRUD server actions. |
| src/app/(internal)/(protected)/(sidebar)/records/page.tsx | Records page with pagination, filters, and export. |
| src/app/(internal)/(protected)/(sidebar)/records/export/route.ts | CSV export route for attendance records with filters. |
| src/app/(internal)/(protected)/(sidebar)/records/actions.tsx | Records fetching + filter option server actions. |
| src/app/(internal)/(protected)/(sidebar)/polls/page.tsx | Polls page with pagination and create dialog. |
| src/app/(internal)/(protected)/(sidebar)/polls/[id]/page.tsx | Poll detail page (actions + QR + results). |
| src/app/(internal)/(protected)/(sidebar)/polls/[id]/edit/page.tsx | Poll edit page wrapper. |
| src/app/(internal)/(protected)/(sidebar)/page.tsx | Dashboard home layout refactor (rooms list + pagination). |
| src/app/(internal)/(protected)/(sidebar)/layout.tsx | Adds inset sidebar layout + site header + tooltips. |
| src/app/(internal)/(protected)/(sidebar)/classes/page.tsx | Classes admin page with pagination. |
| src/app/(internal)/(protected)/(sidebar)/classes/actions.tsx | Classes CRUD server actions + semester ownership checks. |
| src/app/(internal)/(protected)/(sidebar)/attendance/[id]/page.tsx | Removes old header wrapper; renders detail view directly. |
| src/app/(internal)/(protected)/(sidebar)/attendance/[id]/actions.tsx | Extends attendance room query with semester/class relations. |
| package.json | Adds dependencies for new UI primitives, parsing, and radix meta-package. |
| drizzle/meta/_journal.json | Registers new migrations. |
| drizzle/0004_public_hulk.sql | Adds poll.class_id. |
| drizzle/0003_ambiguous_pyro.sql | Creates poll tables. |
| drizzle/0002_public_micromax.sql | Adds attendance_room.class_id and attendant.email. |
| drizzle/0001_warm_sunfire.sql | Creates class + student_class tables; adjusts semester table. |
| components.json | Switches shadcn style preset + config fields. |
| CLAUDE.md | Adds repository overview and contributor guidance. |
Comments suppressed due to low confidence (6)
src/components/pages/attendance/RoomActions.tsx:1
- Unused import updateAttendanceRoom.
src/components/pages/attendance/RoomActions.tsx:2 - Unused import useToast.
src/components/pages/attendance/RoomActions.tsx:3 - Unused import useState.
src/components/pages/attendance/RoomActions.tsx:4 - Unused import useSWRConfig.
src/components/pages/attendance/RoomActions.tsx:6 - Unused import useRouter.
tests/attendance/take-attendance.spec.ts:21 - Unused variable attendantWallet2.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { | ||
| attendanceRecord, | ||
| attendanceRoom, | ||
| attendant, | ||
| studentClass, | ||
| classTable, | ||
| semester, | ||
| } from "@/lib/schema"; | ||
| import { handleDbError } from "@/lib/db.error"; | ||
| import { cookies } from "next/headers"; | ||
| import { eq, and, desc, count, inArray } from "drizzle-orm"; |
There was a problem hiding this comment.
Unused imports (attendant, classTable) should be removed; they aren’t referenced in this module (relations in db.query.* don’t require importing the table here).
| {question.questionType === "MULTIPLE_CHOICE" && ( | ||
| <FormField | ||
| control={form.control} | ||
| name={`question_${question.id}`} | ||
| render={({ field }) => ( | ||
| <FormItem> | ||
| <FormControl> | ||
| <div className="space-y-2"> | ||
| {question.options?.map((option) => ( | ||
| <label | ||
| key={option.id} | ||
| className="flex items-center gap-3 cursor-pointer hover:bg-white p-2 rounded" | ||
| > | ||
| <input | ||
| type="checkbox" | ||
| value={option.id} | ||
| checked={field.value?.includes( | ||
| option.id.toString(), | ||
| )} | ||
| onChange={(e) => { | ||
| const currentValue = field.value || []; | ||
| const newValue = e.target.checked | ||
| ? [...currentValue, option.id.toString()] | ||
| : currentValue.filter( | ||
| (v: string) => | ||
| v !== option.id.toString(), | ||
| ); | ||
| field.onChange(newValue); | ||
| }} | ||
| className="h-4 w-4" | ||
| /> | ||
| <span>{option.optionText}</span> | ||
| </label> | ||
| ))} | ||
| </div> | ||
| </FormControl> | ||
| <FormMessage /> | ||
| </FormItem> |
There was a problem hiding this comment.
Required MULTIPLE_CHOICE questions aren’t actually enforced: checkbox inputs have no required and there’s no RHF validation, so users can submit with an empty selection even when question.isRequired is true. Add a field-level validation rule (e.g., validate: v => !question.isRequired || (v?.length ?? 0) > 0) and surface the error via FormMessage.
| semesterId: integer("semester_id").references(() => semester.id), | ||
| classId: integer("class_id").references(() => classTable.id), |
There was a problem hiding this comment.
These foreign keys default to ON DELETE NO ACTION. With the new UI allowing semester/class deletion, deleting a semester/class that’s referenced by a room will fail with a FK constraint error. Consider setting onDelete: "set null" for semesterId/classId (or explicitly prevent deletion in the actions with a clearer error).
| const Comp = asChild ? Slot.Root : "span" | ||
|
|
||
| return ( | ||
| <Comp | ||
| data-slot="badge" | ||
| data-variant={variant} | ||
| className={cn(badgeVariants({ variant }), className)} | ||
| {...props} |
There was a problem hiding this comment.
Same issue as Button: Slot is a component, so Slot.Root is not valid. This will break asChild badges. Use Slot directly (or import from @radix-ui/react-slot) and render with Comp = asChild ? Slot : "span".
| <NativeModal | ||
| openModal={open} | ||
| closeModal={() => setOpen(false)} | ||
| className="rounded-2xl w-[500px]" | ||
| className="rounded-2xl w-125!" | ||
| > |
There was a problem hiding this comment.
w-125! is not a valid Tailwind utility (important is ! prefix). This class won't take effect and the modal width will be wrong. Use a valid width class like w-[500px] or !w-[500px].
| FormLabel, | ||
| FormMessage, | ||
| } from "@/components/ui/form"; | ||
| import { Input } from "@/components/ui/input"; |
There was a problem hiding this comment.
Unused import Input.
| import { | ||
| pollResponseSchema, | ||
| type PollResponseFormValues, | ||
| } from "../polls/poll.types"; |
There was a problem hiding this comment.
Unused import pollResponseSchema.
| } from "../polls/poll.types"; | ||
| import { submitPollResponse } from "@/app/(public)/poll/[id]/respond/actions"; | ||
| import { useToast } from "@/hooks/use-toast"; | ||
| import Spinner from "@/components/ui/spinner"; |
There was a problem hiding this comment.
Unused import Spinner.
| "use client"; | ||
|
|
||
| import { NativeModal } from "@/context/NativeDialog"; | ||
| import { Plus, Trash2, GripVertical } from "lucide-react"; |
There was a problem hiding this comment.
Unused import GripVertical.
| import { | ||
| createPoll, | ||
| getPolls, | ||
| } from "@/app/(internal)/(protected)/(sidebar)/polls/actions"; |
There was a problem hiding this comment.
Unused import getPolls.
No description provided.