@studious-lms/server 1.24.0 → 1.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/data/curriculum/nepal-cdc-g4-g5/subjects/english.json +4 -4
  2. package/data/curriculum/nepal-cdc-g4-g5/subjects/mathematics.json +1 -1
  3. package/data/curriculum/nepal-cdc-g4-g5/subjects/science-technology.json +4 -4
  4. package/data/curriculum/nepal-cdc-g4-g5/subjects/social-studies.json +4 -4
  5. package/dist/models/attendance.d.ts.map +1 -1
  6. package/dist/models/attendance.js +17 -14
  7. package/dist/models/attendance.js.map +1 -1
  8. package/dist/models/marketplace.d.ts +2 -0
  9. package/dist/models/marketplace.d.ts.map +1 -1
  10. package/dist/models/marketplace.js +3 -2
  11. package/dist/models/marketplace.js.map +1 -1
  12. package/dist/models/moduleItem.d.ts +5 -1
  13. package/dist/models/moduleItem.d.ts.map +1 -1
  14. package/dist/models/moduleItem.js +19 -4
  15. package/dist/models/moduleItem.js.map +1 -1
  16. package/dist/routers/_app.d.ts +8 -6
  17. package/dist/routers/_app.d.ts.map +1 -1
  18. package/dist/routers/fees.d.ts +1 -1
  19. package/dist/routers/moduleItem.d.ts.map +1 -1
  20. package/dist/routers/moduleItem.js +7 -6
  21. package/dist/routers/moduleItem.js.map +1 -1
  22. package/dist/routers/parent.d.ts +2 -1
  23. package/dist/routers/parent.d.ts.map +1 -1
  24. package/dist/routers/school.d.ts +1 -1
  25. package/dist/routers/school.d.ts.map +1 -1
  26. package/dist/routers/school.js +14 -4
  27. package/dist/routers/school.js.map +1 -1
  28. package/dist/services/academicCalendar.d.ts.map +1 -1
  29. package/dist/services/academicCalendar.js +30 -2
  30. package/dist/services/academicCalendar.js.map +1 -1
  31. package/dist/services/attendance.d.ts +6 -2
  32. package/dist/services/attendance.d.ts.map +1 -1
  33. package/dist/services/attendance.js +8 -4
  34. package/dist/services/attendance.js.map +1 -1
  35. package/dist/services/class.d.ts +14 -9
  36. package/dist/services/class.d.ts.map +1 -1
  37. package/dist/services/class.js +4 -4
  38. package/dist/services/class.js.map +1 -1
  39. package/dist/services/fees.d.ts.map +1 -1
  40. package/dist/services/fees.js +24 -4
  41. package/dist/services/fees.js.map +1 -1
  42. package/dist/services/feesAuthz.d.ts +2 -5
  43. package/dist/services/feesAuthz.d.ts.map +1 -1
  44. package/dist/services/feesAuthz.js +5 -8
  45. package/dist/services/feesAuthz.js.map +1 -1
  46. package/dist/services/marketplace.d.ts.map +1 -1
  47. package/dist/services/marketplace.js +8 -5
  48. package/dist/services/marketplace.js.map +1 -1
  49. package/dist/services/moduleItem.d.ts.map +1 -1
  50. package/dist/services/moduleItem.js +23 -7
  51. package/dist/services/moduleItem.js.map +1 -1
  52. package/dist/services/parentPortal.d.ts +3 -5
  53. package/dist/services/parentPortal.d.ts.map +1 -1
  54. package/dist/services/parentPortal.js +29 -43
  55. package/dist/services/parentPortal.js.map +1 -1
  56. package/dist/services/school.d.ts.map +1 -1
  57. package/dist/services/school.js +37 -13
  58. package/dist/services/school.js.map +1 -1
  59. package/dist/services/studentImport.d.ts.map +1 -1
  60. package/dist/services/studentImport.js +38 -25
  61. package/dist/services/studentImport.js.map +1 -1
  62. package/dist/services/transcript.d.ts +2 -3
  63. package/dist/services/transcript.d.ts.map +1 -1
  64. package/dist/services/transcript.js +13 -25
  65. package/dist/services/transcript.js.map +1 -1
  66. package/package.json +1 -1
  67. package/scripts/import-nepal-cdc-curriculum.ts +29 -6
  68. package/src/models/attendance.ts +10 -12
  69. package/src/models/marketplace.ts +3 -0
  70. package/src/models/moduleItem.ts +20 -2
  71. package/src/routers/moduleItem.ts +6 -4
  72. package/src/routers/school.ts +16 -6
  73. package/src/services/academicCalendar.ts +28 -0
  74. package/src/services/attendance.ts +7 -3
  75. package/src/services/class.ts +2 -2
  76. package/src/services/fees.ts +25 -2
  77. package/src/services/feesAuthz.ts +3 -7
  78. package/src/services/marketplace.ts +8 -3
  79. package/src/services/moduleItem.ts +28 -4
  80. package/src/services/parentPortal.ts +26 -39
  81. package/src/services/school.ts +37 -12
  82. package/src/services/studentImport.ts +37 -25
  83. package/src/services/transcript.ts +11 -23
@@ -1 +1 @@
1
- {"version":3,"file":"academicCalendar.js","sources":["services/academicCalendar.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Academic year / term service (C1) + student promotion (C2).\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport {\n createAcademicTerm,\n createAcademicYear,\n deleteAcademicTerm,\n deleteAcademicYear,\n getAcademicYearById,\n getCurrentAcademicYear,\n listAcademicYears,\n updateAcademicTerm,\n updateAcademicYear,\n} from \"../models/academicCalendar.js\";\nimport {\n findActiveSchoolAdminMembership,\n findSchoolClass,\n listActiveSchoolMemberships,\n} from \"../models/school.js\";\n\nasync function requireSchoolAdmin(schoolId: string, userId: string) {\n const membership = await findActiveSchoolAdminMembership(schoolId, userId);\n if (!membership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can perform this action\",\n });\n }\n return membership;\n}\n\nexport async function listYears(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n return { years: await listAcademicYears(schoolId) };\n}\n\nexport async function getCurrentYear(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n return { year: await getCurrentAcademicYear(schoolId) };\n}\n\nexport async function createYear(\n userId: string,\n input: {\n schoolId: string;\n name: string;\n startDate: Date;\n endDate: Date;\n isCurrent?: boolean;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n if (input.endDate < input.startDate) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"endDate must be on or after startDate\",\n });\n }\n try {\n const year = await createAcademicYear(input);\n return { year };\n } catch (err: unknown) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n (err as { code: string }).code === \"P2002\"\n ) {\n throw new TRPCError({\n code: \"CONFLICT\",\n message: \"An academic year with this name already exists\",\n });\n }\n throw err;\n }\n}\n\nexport async function updateYear(\n userId: string,\n input: {\n schoolId: string;\n yearId: string;\n name?: string;\n startDate?: Date;\n endDate?: Date;\n isCurrent?: boolean;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const year = await updateAcademicYear(input.yearId, input.schoolId, {\n name: input.name,\n startDate: input.startDate,\n endDate: input.endDate,\n isCurrent: input.isCurrent,\n });\n if (!year) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic year not found\" });\n }\n return { year };\n}\n\nexport async function removeYear(\n userId: string,\n input: { schoolId: string; yearId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const result = await deleteAcademicYear(input.yearId, input.schoolId);\n if (result.count === 0) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic year not found\" });\n }\n return { ok: true as const };\n}\n\nexport async function createTerm(\n userId: string,\n input: {\n schoolId: string;\n yearId: string;\n name: string;\n startDate: Date;\n endDate: Date;\n isCurrent?: boolean;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const year = await getAcademicYearById(input.yearId, input.schoolId);\n if (!year) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic year not found\" });\n }\n if (input.endDate < input.startDate) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"endDate must be on or after startDate\",\n });\n }\n try {\n const term = await createAcademicTerm({\n academicYearId: input.yearId,\n name: input.name,\n startDate: input.startDate,\n endDate: input.endDate,\n isCurrent: input.isCurrent,\n });\n return { term };\n } catch (err: unknown) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n (err as { code: string }).code === \"P2002\"\n ) {\n throw new TRPCError({\n code: \"CONFLICT\",\n message: \"A term with this name already exists in the year\",\n });\n }\n throw err;\n }\n}\n\nexport async function updateTerm(\n userId: string,\n input: {\n schoolId: string;\n yearId: string;\n termId: string;\n name?: string;\n startDate?: Date;\n endDate?: Date;\n isCurrent?: boolean;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const year = await getAcademicYearById(input.yearId, input.schoolId);\n if (!year) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic year not found\" });\n }\n const term = await updateAcademicTerm(input.termId, input.yearId, {\n name: input.name,\n startDate: input.startDate,\n endDate: input.endDate,\n isCurrent: input.isCurrent,\n });\n if (!term) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic term not found\" });\n }\n return { term };\n}\n\nexport async function removeTerm(\n userId: string,\n input: { schoolId: string; yearId: string; termId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const year = await getAcademicYearById(input.yearId, input.schoolId);\n if (!year) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic year not found\" });\n }\n const result = await deleteAcademicTerm(input.termId, input.yearId);\n if (result.count === 0) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic term not found\" });\n }\n return { ok: true as const };\n}\n\n/**\n * C2: Promote / move students from one class to another (basic rollover).\n * Disconnects from `fromClassId` and connects to `toClassId`.\n */\nexport async function promoteStudents(\n userId: string,\n input: {\n schoolId: string;\n fromClassId: string;\n toClassId: string;\n studentUserIds: string[];\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n if (input.fromClassId === input.toClassId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"fromClassId and toClassId must differ\",\n });\n }\n if (input.studentUserIds.length === 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Select at least one student\",\n });\n }\n\n const [fromClass, toClass] = await Promise.all([\n findSchoolClass(input.schoolId, input.fromClassId),\n findSchoolClass(input.schoolId, input.toClassId),\n ]);\n if (!fromClass || !toClass) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Source or destination class not found in this school\",\n });\n }\n\n const memberships = await listActiveSchoolMemberships(\n input.schoolId,\n input.studentUserIds\n );\n const studentIds = memberships\n .filter((m) => m.role === \"STUDENT\")\n .map((m) => m.userId);\n if (studentIds.length === 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No active student memberships found for the given users\",\n });\n }\n\n // Only move students currently enrolled in the source class.\n const enrolled = await prisma.class.findFirst({\n where: {\n id: input.fromClassId,\n schoolId: input.schoolId,\n },\n select: {\n students: {\n where: { id: { in: studentIds } },\n select: { id: true },\n },\n },\n });\n const moveIds = (enrolled?.students ?? []).map((s) => s.id);\n if (moveIds.length === 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"None of the selected students are in the source class\",\n });\n }\n\n await prisma.$transaction([\n prisma.class.update({\n where: { id: input.fromClassId },\n data: { students: { disconnect: moveIds.map((id) => ({ id })) } },\n }),\n prisma.class.update({\n where: { id: input.toClassId },\n data: { students: { connect: moveIds.map((id) => ({ id })) } },\n }),\n ]);\n\n return {\n promotedCount: moveIds.length,\n studentUserIds: moveIds,\n fromClassId: input.fromClassId,\n toClassId: input.toClassId,\n };\n}\n"],"names":[],"mappings":"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","debug_id":"97525cba-13be-5926-93dc-e0cbf27e0ef6"}
1
+ {"version":3,"file":"academicCalendar.js","sources":["services/academicCalendar.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Academic year / term service (C1) + student promotion (C2).\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport {\n createAcademicTerm,\n createAcademicYear,\n deleteAcademicTerm,\n deleteAcademicYear,\n getAcademicYearById,\n getCurrentAcademicYear,\n listAcademicYears,\n updateAcademicTerm,\n updateAcademicYear,\n} from \"../models/academicCalendar.js\";\nimport {\n findActiveSchoolAdminMembership,\n findSchoolClass,\n listActiveSchoolMemberships,\n} from \"../models/school.js\";\n\nasync function requireSchoolAdmin(schoolId: string, userId: string) {\n const membership = await findActiveSchoolAdminMembership(schoolId, userId);\n if (!membership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can perform this action\",\n });\n }\n return membership;\n}\n\nexport async function listYears(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n return { years: await listAcademicYears(schoolId) };\n}\n\nexport async function getCurrentYear(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n return { year: await getCurrentAcademicYear(schoolId) };\n}\n\nexport async function createYear(\n userId: string,\n input: {\n schoolId: string;\n name: string;\n startDate: Date;\n endDate: Date;\n isCurrent?: boolean;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n if (input.endDate < input.startDate) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"endDate must be on or after startDate\",\n });\n }\n try {\n const year = await createAcademicYear(input);\n return { year };\n } catch (err: unknown) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n (err as { code: string }).code === \"P2002\"\n ) {\n throw new TRPCError({\n code: \"CONFLICT\",\n message: \"An academic year with this name already exists\",\n });\n }\n throw err;\n }\n}\n\nexport async function updateYear(\n userId: string,\n input: {\n schoolId: string;\n yearId: string;\n name?: string;\n startDate?: Date;\n endDate?: Date;\n isCurrent?: boolean;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n if (input.startDate !== undefined || input.endDate !== undefined) {\n const existing = await getAcademicYearById(input.yearId, input.schoolId);\n if (!existing) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic year not found\" });\n }\n const nextStart = input.startDate ?? existing.startDate;\n const nextEnd = input.endDate ?? existing.endDate;\n if (nextEnd < nextStart) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"endDate must be on or after startDate\",\n });\n }\n }\n const year = await updateAcademicYear(input.yearId, input.schoolId, {\n name: input.name,\n startDate: input.startDate,\n endDate: input.endDate,\n isCurrent: input.isCurrent,\n });\n if (!year) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic year not found\" });\n }\n return { year };\n}\n\nexport async function removeYear(\n userId: string,\n input: { schoolId: string; yearId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const result = await deleteAcademicYear(input.yearId, input.schoolId);\n if (result.count === 0) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic year not found\" });\n }\n return { ok: true as const };\n}\n\nexport async function createTerm(\n userId: string,\n input: {\n schoolId: string;\n yearId: string;\n name: string;\n startDate: Date;\n endDate: Date;\n isCurrent?: boolean;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const year = await getAcademicYearById(input.yearId, input.schoolId);\n if (!year) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic year not found\" });\n }\n if (input.endDate < input.startDate) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"endDate must be on or after startDate\",\n });\n }\n try {\n const term = await createAcademicTerm({\n academicYearId: input.yearId,\n name: input.name,\n startDate: input.startDate,\n endDate: input.endDate,\n isCurrent: input.isCurrent,\n });\n return { term };\n } catch (err: unknown) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n (err as { code: string }).code === \"P2002\"\n ) {\n throw new TRPCError({\n code: \"CONFLICT\",\n message: \"A term with this name already exists in the year\",\n });\n }\n throw err;\n }\n}\n\nexport async function updateTerm(\n userId: string,\n input: {\n schoolId: string;\n yearId: string;\n termId: string;\n name?: string;\n startDate?: Date;\n endDate?: Date;\n isCurrent?: boolean;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const year = await getAcademicYearById(input.yearId, input.schoolId);\n if (!year) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic year not found\" });\n }\n if (input.startDate !== undefined || input.endDate !== undefined) {\n const existingTerm = year.terms.find((t) => t.id === input.termId);\n if (!existingTerm) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic term not found\" });\n }\n const nextStart = input.startDate ?? existingTerm.startDate;\n const nextEnd = input.endDate ?? existingTerm.endDate;\n if (nextEnd < nextStart) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"endDate must be on or after startDate\",\n });\n }\n }\n const term = await updateAcademicTerm(input.termId, input.yearId, {\n name: input.name,\n startDate: input.startDate,\n endDate: input.endDate,\n isCurrent: input.isCurrent,\n });\n if (!term) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic term not found\" });\n }\n return { term };\n}\n\nexport async function removeTerm(\n userId: string,\n input: { schoolId: string; yearId: string; termId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const year = await getAcademicYearById(input.yearId, input.schoolId);\n if (!year) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic year not found\" });\n }\n const result = await deleteAcademicTerm(input.termId, input.yearId);\n if (result.count === 0) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Academic term not found\" });\n }\n return { ok: true as const };\n}\n\n/**\n * C2: Promote / move students from one class to another (basic rollover).\n * Disconnects from `fromClassId` and connects to `toClassId`.\n */\nexport async function promoteStudents(\n userId: string,\n input: {\n schoolId: string;\n fromClassId: string;\n toClassId: string;\n studentUserIds: string[];\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n if (input.fromClassId === input.toClassId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"fromClassId and toClassId must differ\",\n });\n }\n if (input.studentUserIds.length === 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Select at least one student\",\n });\n }\n\n const [fromClass, toClass] = await Promise.all([\n findSchoolClass(input.schoolId, input.fromClassId),\n findSchoolClass(input.schoolId, input.toClassId),\n ]);\n if (!fromClass || !toClass) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Source or destination class not found in this school\",\n });\n }\n\n const memberships = await listActiveSchoolMemberships(\n input.schoolId,\n input.studentUserIds\n );\n const studentIds = memberships\n .filter((m) => m.role === \"STUDENT\")\n .map((m) => m.userId);\n if (studentIds.length === 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No active student memberships found for the given users\",\n });\n }\n\n // Only move students currently enrolled in the source class.\n const enrolled = await prisma.class.findFirst({\n where: {\n id: input.fromClassId,\n schoolId: input.schoolId,\n },\n select: {\n students: {\n where: { id: { in: studentIds } },\n select: { id: true },\n },\n },\n });\n const moveIds = (enrolled?.students ?? []).map((s) => s.id);\n if (moveIds.length === 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"None of the selected students are in the source class\",\n });\n }\n\n await prisma.$transaction([\n prisma.class.update({\n where: { id: input.fromClassId },\n data: { students: { disconnect: moveIds.map((id) => ({ id })) } },\n }),\n prisma.class.update({\n where: { id: input.toClassId },\n data: { students: { connect: moveIds.map((id) => ({ id })) } },\n }),\n ]);\n\n return {\n promotedCount: moveIds.length,\n studentUserIds: moveIds,\n fromClassId: input.fromClassId,\n toClassId: input.toClassId,\n };\n}\n"],"names":[],"mappings":"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","debug_id":"d8dde89c-b5a2-5b31-be33-b365078aeaa2"}
@@ -183,7 +183,11 @@ export declare function updateAttendanceRecord(userId: string, classId: string,
183
183
  } | null;
184
184
  }[];
185
185
  }>;
186
- /** School-admin: today's attendance rollup across classes. */
186
+ /**
187
+ * School-admin: today's attendance rollup across classes.
188
+ * `percentage` is session-weighted (share of attended class-session records),
189
+ * not a share of `totalStudents`; a student in six classes contributes six records.
190
+ */
187
191
  export declare function listTodayAttendanceSummary(userId: string, schoolId: string): Promise<{
188
192
  date: Date;
189
193
  totalStudents: number;
@@ -244,7 +248,7 @@ export declare function listExcusals(userId: string, input: {
244
248
  revokedAt: Date | null;
245
249
  createdAt: Date;
246
250
  updatedAt: Date;
247
- status: "ACTIVE" | "REVOKED" | "UPCOMING";
251
+ status: "ACTIVE" | "REVOKED" | "EXPIRED" | "UPCOMING";
248
252
  studentIds: string[];
249
253
  students: {
250
254
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"attendance.d.ts","sourceRoot":"/","sources":["services/attendance.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"attendance.d.ts","sourceRoot":"/","sources":["services/attendance.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@
4
4
  * Active StudentExcusal rows force EXCUSED (locked for teachers).
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="61646503-b6ff-5d4c-8251-5ecf346dad65")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a0baad8d-f286-5756-9dfd-397505318152")}catch(e){}}();
8
8
  import { TRPCError } from "@trpc/server";
9
9
  import { findClassWithStudents, findClassWithTeacher, findEventsByClassId, findAttendanceByEventId, findAttendanceByClassAndEvent, findManyAttendance, createAttendance, createAttendanceForEvent, updateAttendance, findActiveExcusalsForStudents, listExcusalsForSchool, findExcusalById, createStudentExcusal, updateStudentExcusal, revokeStudentExcusal, applyExcusalToAttendance, clearExcusalLocks, listSchoolStudentMemberships, listAttendanceRecordsForSchoolStudents, listTodaySchoolAttendanceSessions, toDateOnly, startOfUtcDay, endOfUtcDay, } from "../models/attendance.js";
10
10
  import { findActiveSchoolAdminMembership } from "../models/school.js";
@@ -192,7 +192,11 @@ export async function updateAttendanceRecord(userId, classId, eventId, attendanc
192
192
  });
193
193
  return shapeAttendanceSession(updated);
194
194
  }
195
- /** School-admin: today's attendance rollup across classes. */
195
+ /**
196
+ * School-admin: today's attendance rollup across classes.
197
+ * `percentage` is session-weighted (share of attended class-session records),
198
+ * not a share of `totalStudents`; a student in six classes contributes six records.
199
+ */
196
200
  export async function listTodayAttendanceSummary(userId, schoolId) {
197
201
  await requireSchoolAdmin(schoolId, userId);
198
202
  const today = new Date();
@@ -303,7 +307,7 @@ export async function listExcusals(userId, input) {
303
307
  status = "UPCOMING";
304
308
  }
305
309
  else if (toDateOnly(excusal.endDate) < now) {
306
- status = "ACTIVE"; // past but not revoked — still listed as ACTIVE historically
310
+ status = "EXPIRED";
307
311
  }
308
312
  return {
309
313
  id: excusal.id,
@@ -490,4 +494,4 @@ async function sendAttendanceNotification(input) {
490
494
  // Re-export date helpers used by callers/tests.
491
495
  export { toDateOnly, startOfUtcDay, endOfUtcDay };
492
496
  //# sourceMappingURL=attendance.js.map
493
- //# debugId=61646503-b6ff-5d4c-8251-5ecf346dad65
497
+ //# debugId=a0baad8d-f286-5756-9dfd-397505318152
@@ -1 +1 @@
1
- {"version":3,"file":"attendance.js","sources":["services/attendance.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Attendance service – class attendance + school-admin excusals / stats.\n * Dual-writes legacy present/late/absent lists and per-student AttendanceRecord.\n * Active StudentExcusal rows force EXCUSED (locked for teachers).\n */\nimport { TRPCError } from \"@trpc/server\";\nimport {\n findClassWithStudents,\n findClassWithTeacher,\n findEventsByClassId,\n findAttendanceByEventId,\n findAttendanceByClassAndEvent,\n findManyAttendance,\n createAttendance,\n createAttendanceForEvent,\n updateAttendance,\n findActiveExcusalsForStudents,\n listExcusalsForSchool,\n findExcusalById,\n createStudentExcusal,\n updateStudentExcusal,\n revokeStudentExcusal,\n applyExcusalToAttendance,\n clearExcusalLocks,\n listSchoolStudentMemberships,\n listAttendanceRecordsForSchoolStudents,\n listTodaySchoolAttendanceSessions,\n toDateOnly,\n startOfUtcDay,\n endOfUtcDay,\n} from \"../models/attendance.js\";\nimport { findActiveSchoolAdminMembership } from \"../models/school.js\";\nimport { sendToMultiple } from \"./notification.js\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n buildExcusalLocks,\n mergeAttendanceUpdateWithLocks,\n type StudentRef,\n} from \"./attendanceMerge.js\";\nimport {\n computeAttendancePercentage,\n emptyAttendanceCounts,\n tallyAttendanceStatuses,\n} from \"./attendanceStats.js\";\n\nasync function requireSchoolAdmin(schoolId: string, userId: string) {\n const membership = await findActiveSchoolAdminMembership(schoolId, userId);\n if (!membership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can perform this action\",\n });\n }\n return membership;\n}\n\nfunction sessionDate(attendance: {\n date: Date;\n event?: { startTime: Date } | null;\n}): Date {\n return attendance.event?.startTime ?? attendance.date;\n}\n\n/** Get attendance for a class (optionally filtered by event). Creates missing records. */\nexport async function getAttendance(classId: string, eventId?: string) {\n const classData = await findClassWithStudents(classId);\n if (!classData) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to view this class's attendance\",\n });\n }\n\n const events = await findEventsByClassId(classId);\n const studentIds = classData.students.map((s) => s.id);\n\n for (const event of events) {\n const existing = await findAttendanceByEventId(event.id);\n if (!existing) {\n const locks =\n classData.schoolId && studentIds.length > 0\n ? buildExcusalLocks(\n await findActiveExcusalsForStudents({\n schoolId: classData.schoolId,\n studentIds,\n date: event.startTime,\n }),\n studentIds\n )\n : [];\n\n const merged = mergeAttendanceUpdateWithLocks({\n present: classData.students.map((s) => ({\n id: s.id,\n username: s.username,\n })),\n late: [],\n absent: [],\n locks,\n });\n\n await createAttendanceForEvent({\n classId,\n eventId: event.id,\n date: event.startTime,\n presentIds: merged.presentIds,\n lateIds: merged.lateIds,\n absentIds: merged.absentIds,\n excusedIds: merged.excusedIds,\n records: merged.records,\n });\n } else if (classData.schoolId && studentIds.length > 0) {\n // Ensure active excusals are reflected on existing sessions.\n const locks = buildExcusalLocks(\n await findActiveExcusalsForStudents({\n schoolId: classData.schoolId,\n studentIds,\n date: event.startTime,\n }),\n studentIds\n );\n const needsLock = locks.filter((lock) => {\n const current = existing.records.find((r) => r.studentId === lock.studentId);\n return !(\n current?.status === \"EXCUSED\" &&\n current.excusedByExcusalId === lock.excusalId\n );\n });\n const byExcusal = new Map<string, string[]>();\n for (const lock of needsLock) {\n const list = byExcusal.get(lock.excusalId) ?? [];\n list.push(lock.studentId);\n byExcusal.set(lock.excusalId, list);\n }\n for (const [excusalId, lockedStudentIds] of byExcusal) {\n await applyExcusalToAttendance({\n schoolId: classData.schoolId,\n excusalId,\n studentIds: lockedStudentIds,\n startDate: event.startTime,\n endDate: event.startTime,\n });\n }\n }\n }\n\n const sessions = await findManyAttendance(classId, eventId);\n return sessions.map(shapeAttendanceSession);\n}\n\n/** Additive shape: keep present/late/absent; expose excused + lock metadata for UI. */\nfunction shapeAttendanceSession<\n T extends {\n records: Array<{\n id: string;\n studentId: string;\n status: string;\n note: string | null;\n excusedByExcusalId: string | null;\n updatedById: string | null;\n updatedAt: Date;\n student: { id: string; username: string };\n excusedByExcusal: {\n id: string;\n reason: string;\n note: string | null;\n } | null;\n }>;\n present: unknown[];\n late: unknown[];\n absent: unknown[];\n },\n>(session: T) {\n const records = session.records.map((r) => ({\n ...r,\n lockedFromExcusal: Boolean(r.excusedByExcusalId),\n reason: r.excusedByExcusal?.reason ?? null,\n excusalNote: r.excusedByExcusal?.note ?? null,\n }));\n const excused = records\n .filter((r) => r.status === \"EXCUSED\")\n .map((r) => r.student);\n\n return {\n ...session,\n excused,\n records,\n };\n}\n\n/** Update attendance record (present/late/absent/excused). Teacher-only. */\nexport async function updateAttendanceRecord(\n userId: string,\n classId: string,\n eventId: string | null | undefined,\n attendance: {\n present: StudentRef[];\n late: StudentRef[];\n absent: StudentRef[];\n excused?: StudentRef[];\n }\n) {\n const classData = await findClassWithTeacher(classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to update this class's attendance\",\n });\n }\n\n const existing = await findAttendanceByClassAndEvent(classId, eventId ?? null);\n const dateForExcusal = existing\n ? sessionDate(existing)\n : new Date();\n\n const classStudentIds = classData.students.map((s) => s.id);\n const locks =\n classData.schoolId && classStudentIds.length > 0\n ? buildExcusalLocks(\n await findActiveExcusalsForStudents({\n schoolId: classData.schoolId,\n studentIds: classStudentIds,\n date: dateForExcusal,\n }),\n classStudentIds\n )\n : [];\n\n const existingNotes = new Map(\n (existing?.records ?? []).map((r) => [r.studentId, r.note])\n );\n\n const merged = mergeAttendanceUpdateWithLocks({\n present: attendance.present,\n late: attendance.late,\n absent: attendance.absent,\n excused: attendance.excused,\n locks,\n updatedById: userId,\n existingNotesByStudentId: existingNotes,\n });\n\n const previousLateIds = new Set(existing?.late.map((student) => student.id) ?? []);\n const previousAbsentIds = new Set(\n existing?.absent.map((student) => student.id) ?? []\n );\n const classStudentIdSet = new Set(classStudentIds);\n\n if (!existing) {\n const created = await createAttendance({\n classId,\n eventId: eventId ?? null,\n presentIds: merged.presentIds,\n lateIds: merged.lateIds,\n absentIds: merged.absentIds,\n excusedIds: merged.excusedIds,\n records: merged.records,\n updatedById: userId,\n });\n await notifyMarkedLateOrAbsent({\n classId,\n className: classData.name,\n eventId: eventId ?? null,\n eventName: created.event?.name ?? null,\n classStudentIds: classStudentIdSet,\n lateIds: merged.lateIds,\n absentIds: merged.absentIds,\n previousLateIds,\n previousAbsentIds,\n });\n return shapeAttendanceSession(created);\n }\n\n const updated = await updateAttendance(existing.id, {\n presentIds: merged.presentIds,\n lateIds: merged.lateIds,\n absentIds: merged.absentIds,\n records: merged.records,\n });\n await notifyMarkedLateOrAbsent({\n classId,\n className: classData.name,\n eventId: eventId ?? null,\n eventName: existing.event?.name ?? null,\n classStudentIds: classStudentIdSet,\n lateIds: merged.lateIds,\n absentIds: merged.absentIds,\n previousLateIds,\n previousAbsentIds,\n });\n return shapeAttendanceSession(updated);\n}\n\n/** School-admin: today's attendance rollup across classes. */\nexport async function listTodayAttendanceSummary(\n userId: string,\n schoolId: string\n) {\n await requireSchoolAdmin(schoolId, userId);\n\n const today = new Date();\n const sessions = await listTodaySchoolAttendanceSessions(schoolId, today);\n const memberships = await listSchoolStudentMemberships(schoolId);\n const totalStudents = memberships.length;\n\n const counts = emptyAttendanceCounts();\n const rows: Array<{\n attendanceId: string;\n classId: string;\n className: string;\n section: string;\n subject: string;\n eventId: string | null;\n eventName: string | null;\n date: Date;\n present: number;\n late: number;\n absent: number;\n excused: number;\n unmarked: number;\n classStudentCount: number;\n }> = [];\n\n for (const session of sessions) {\n const tallied = tallyAttendanceStatuses(session.records.map((r) => r.status));\n counts.present += tallied.present;\n counts.late += tallied.late;\n counts.absent += tallied.absent;\n counts.excused += tallied.excused;\n const classStudentCount = session.class._count.students;\n const marked =\n tallied.present + tallied.late + tallied.absent + tallied.excused;\n rows.push({\n attendanceId: session.id,\n classId: session.classId,\n className: session.class.name,\n section: session.class.section,\n subject: session.class.subject,\n eventId: session.eventId,\n eventName: session.event?.name ?? null,\n date: session.event?.startTime ?? session.date,\n present: tallied.present,\n late: tallied.late,\n absent: tallied.absent,\n excused: tallied.excused,\n unmarked: Math.max(0, classStudentCount - marked),\n classStudentCount,\n });\n }\n\n return {\n date: toDateOnly(today),\n totalStudents,\n totals: counts,\n percentage: computeAttendancePercentage(counts),\n sessions: rows,\n };\n}\n\n/** School-admin: per-student attendance counts + % (excused excluded from %). */\nexport async function listStudentAttendanceStats(\n userId: string,\n input: {\n schoolId: string;\n from?: Date;\n to?: Date;\n studentId?: string;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n const memberships = await listSchoolStudentMemberships(input.schoolId);\n const filtered = input.studentId\n ? memberships.filter((m) => m.userId === input.studentId)\n : memberships;\n const studentIds = filtered.map((m) => m.userId);\n\n const records = await listAttendanceRecordsForSchoolStudents({\n schoolId: input.schoolId,\n studentIds,\n from: input.from,\n to: input.to,\n });\n\n const byStudent = new Map<string, ReturnType<typeof emptyAttendanceCounts>>();\n for (const id of studentIds) {\n byStudent.set(id, emptyAttendanceCounts());\n }\n for (const record of records) {\n const counts = byStudent.get(record.studentId);\n if (!counts) continue;\n switch (record.status) {\n case \"PRESENT\":\n counts.present += 1;\n break;\n case \"LATE\":\n counts.late += 1;\n break;\n case \"ABSENT\":\n counts.absent += 1;\n break;\n case \"EXCUSED\":\n counts.excused += 1;\n break;\n default:\n break;\n }\n }\n\n return filtered.map((membership) => {\n const counts = byStudent.get(membership.userId) ?? emptyAttendanceCounts();\n return {\n studentId: membership.userId,\n username: membership.user.username,\n displayName: membership.user.profile?.displayName ?? null,\n profilePicture: membership.user.profile?.profilePicture ?? null,\n profilePictureThumbnail:\n membership.user.profile?.profilePictureThumbnail ?? null,\n classes: membership.user.studentIn,\n present: counts.present,\n late: counts.late,\n absent: counts.absent,\n excused: counts.excused,\n attendancePercentage: computeAttendancePercentage(counts),\n };\n });\n}\n\nexport async function listExcusals(\n userId: string,\n input: {\n schoolId: string;\n includeRevoked?: boolean;\n studentId?: string;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n const excusals = await listExcusalsForSchool(input);\n const now = toDateOnly(new Date());\n\n return excusals.map((excusal) => {\n let status: \"ACTIVE\" | \"UPCOMING\" | \"REVOKED\" = \"ACTIVE\";\n if (excusal.revokedAt) {\n status = \"REVOKED\";\n } else if (toDateOnly(excusal.startDate) > now) {\n status = \"UPCOMING\";\n } else if (toDateOnly(excusal.endDate) < now) {\n status = \"ACTIVE\"; // past but not revoked — still listed as ACTIVE historically\n }\n\n return {\n id: excusal.id,\n schoolId: excusal.schoolId,\n startDate: excusal.startDate,\n endDate: excusal.endDate,\n reason: excusal.reason,\n note: excusal.note,\n revokedAt: excusal.revokedAt,\n createdAt: excusal.createdAt,\n updatedAt: excusal.updatedAt,\n status,\n studentIds: excusal.students.map((s) => s.studentId),\n students: excusal.students.map((s) => ({\n id: s.student.id,\n username: s.student.username,\n displayName: s.student.profile?.displayName ?? null,\n profilePicture: s.student.profile?.profilePicture ?? null,\n profilePictureThumbnail:\n s.student.profile?.profilePictureThumbnail ?? null,\n })),\n createdBy: {\n id: excusal.createdBy.id,\n username: excusal.createdBy.username,\n displayName: excusal.createdBy.profile?.displayName ?? null,\n },\n revokedBy: excusal.revokedBy\n ? {\n id: excusal.revokedBy.id,\n username: excusal.revokedBy.username,\n displayName: excusal.revokedBy.profile?.displayName ?? null,\n }\n : null,\n };\n });\n}\n\nexport async function createExcusal(\n userId: string,\n input: {\n schoolId: string;\n studentIds: string[];\n startDate: Date;\n endDate: Date;\n reason: string;\n note?: string | null;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n if (toDateOnly(input.endDate) < toDateOnly(input.startDate)) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"endDate must be on or after startDate\",\n });\n }\n\n const uniqueStudentIds = [...new Set(input.studentIds)];\n const memberships = await listSchoolStudentMemberships(input.schoolId);\n const schoolStudentIds = new Set(memberships.map((m) => m.userId));\n const invalid = uniqueStudentIds.filter((id) => !schoolStudentIds.has(id));\n if (invalid.length > 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"One or more students are not active members of this school\",\n });\n }\n\n const excusal = await createStudentExcusal({\n schoolId: input.schoolId,\n studentIds: uniqueStudentIds,\n startDate: input.startDate,\n endDate: input.endDate,\n reason: input.reason,\n note: input.note,\n createdById: userId,\n });\n\n await applyExcusalToAttendance({\n schoolId: input.schoolId,\n excusalId: excusal.id,\n studentIds: uniqueStudentIds,\n startDate: input.startDate,\n endDate: input.endDate,\n updatedById: userId,\n });\n\n return excusal;\n}\n\nexport async function updateExcusal(\n userId: string,\n input: {\n schoolId: string;\n excusalId: string;\n studentIds?: string[];\n startDate?: Date;\n endDate?: Date;\n reason?: string;\n note?: string | null;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n const existing = await findExcusalById(input.excusalId);\n if (!existing || existing.schoolId !== input.schoolId) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Excusal not found\" });\n }\n if (existing.revokedAt) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot update a revoked excusal\",\n });\n }\n\n const startDate = input.startDate ?? existing.startDate;\n const endDate = input.endDate ?? existing.endDate;\n if (toDateOnly(endDate) < toDateOnly(startDate)) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"endDate must be on or after startDate\",\n });\n }\n\n let studentIds = input.studentIds\n ? [...new Set(input.studentIds)]\n : existing.students.map((s) => s.studentId);\n\n if (input.studentIds) {\n const memberships = await listSchoolStudentMemberships(input.schoolId);\n const schoolStudentIds = new Set(memberships.map((m) => m.userId));\n const invalid = studentIds.filter((id) => !schoolStudentIds.has(id));\n if (invalid.length > 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"One or more students are not active members of this school\",\n });\n }\n }\n\n // Clear previous locks, then re-apply for the new window/students.\n await clearExcusalLocks(input.excusalId);\n\n const updated = await updateStudentExcusal(input.excusalId, {\n studentIds: input.studentIds ? studentIds : undefined,\n startDate: input.startDate,\n endDate: input.endDate,\n reason: input.reason,\n note: input.note,\n });\n\n await applyExcusalToAttendance({\n schoolId: input.schoolId,\n excusalId: updated.id,\n studentIds,\n startDate,\n endDate,\n updatedById: userId,\n });\n\n return updated;\n}\n\nexport async function revokeExcusal(\n userId: string,\n input: { schoolId: string; excusalId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n const existing = await findExcusalById(input.excusalId);\n if (!existing || existing.schoolId !== input.schoolId) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Excusal not found\" });\n }\n if (existing.revokedAt) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Excusal is already revoked\",\n });\n }\n\n await clearExcusalLocks(input.excusalId);\n return revokeStudentExcusal(input.excusalId, userId);\n}\n\n/** Notify only students whose late or absent status is newly added. */\nasync function notifyMarkedLateOrAbsent(input: {\n classId: string;\n className: string;\n eventId: string | null;\n eventName: string | null;\n classStudentIds: Set<string>;\n lateIds: string[];\n absentIds: string[];\n previousLateIds: Set<string>;\n previousAbsentIds: Set<string>;\n}) {\n const lateReceiverIds = [...new Set(input.lateIds)].filter(\n (id) => input.classStudentIds.has(id) && !input.previousLateIds.has(id)\n );\n const absentReceiverIds = [...new Set(input.absentIds)].filter(\n (id) => input.classStudentIds.has(id) && !input.previousAbsentIds.has(id)\n );\n const link = input.eventId\n ? `/class/${input.classId}/attendance/${input.eventId}`\n : `/class/${input.classId}/attendance`;\n const attendanceLabel = input.eventName\n ? `\"${input.eventName}\" in ${input.className}`\n : input.className;\n\n await Promise.all([\n sendAttendanceNotification({\n receiverIds: lateReceiverIds,\n title: `Marked late in ${input.className}`,\n content: `You were marked late for ${attendanceLabel}.\\n[View attendance](${link})`,\n type: \"ATTENDANCE\",\n entityType: \"ATTENDANCE\",\n entityId: input.eventId,\n classId: input.classId,\n }),\n sendAttendanceNotification({\n receiverIds: absentReceiverIds,\n title: `Marked absent in ${input.className}`,\n content: `You were marked absent for ${attendanceLabel}.\\n[View attendance](${link})`,\n type: \"ATTENDANCE\",\n entityType: \"ATTENDANCE\",\n entityId: input.eventId,\n classId: input.classId,\n }),\n ]);\n}\n\n/** Send attendance notifications without failing the attendance update itself. */\nasync function sendAttendanceNotification(input: {\n receiverIds: string[];\n title: string;\n content: string;\n type: \"ATTENDANCE\";\n entityType: string;\n entityId: string | null;\n classId: string;\n}) {\n if (input.receiverIds.length === 0) {\n return;\n }\n\n try {\n await sendToMultiple(input);\n } catch (error) {\n logger.error(\"Failed to send attendance notifications:\", { error });\n }\n}\n\n// Re-export date helpers used by callers/tests.\nexport { toDateOnly, startOfUtcDay, endOfUtcDay };\n"],"names":[],"mappings":"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","debug_id":"61646503-b6ff-5d4c-8251-5ecf346dad65"}
1
+ {"version":3,"file":"attendance.js","sources":["services/attendance.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Attendance service – class attendance + school-admin excusals / stats.\n * Dual-writes legacy present/late/absent lists and per-student AttendanceRecord.\n * Active StudentExcusal rows force EXCUSED (locked for teachers).\n */\nimport { TRPCError } from \"@trpc/server\";\nimport {\n findClassWithStudents,\n findClassWithTeacher,\n findEventsByClassId,\n findAttendanceByEventId,\n findAttendanceByClassAndEvent,\n findManyAttendance,\n createAttendance,\n createAttendanceForEvent,\n updateAttendance,\n findActiveExcusalsForStudents,\n listExcusalsForSchool,\n findExcusalById,\n createStudentExcusal,\n updateStudentExcusal,\n revokeStudentExcusal,\n applyExcusalToAttendance,\n clearExcusalLocks,\n listSchoolStudentMemberships,\n listAttendanceRecordsForSchoolStudents,\n listTodaySchoolAttendanceSessions,\n toDateOnly,\n startOfUtcDay,\n endOfUtcDay,\n} from \"../models/attendance.js\";\nimport { findActiveSchoolAdminMembership } from \"../models/school.js\";\nimport { sendToMultiple } from \"./notification.js\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n buildExcusalLocks,\n mergeAttendanceUpdateWithLocks,\n type StudentRef,\n} from \"./attendanceMerge.js\";\nimport {\n computeAttendancePercentage,\n emptyAttendanceCounts,\n tallyAttendanceStatuses,\n} from \"./attendanceStats.js\";\n\nasync function requireSchoolAdmin(schoolId: string, userId: string) {\n const membership = await findActiveSchoolAdminMembership(schoolId, userId);\n if (!membership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can perform this action\",\n });\n }\n return membership;\n}\n\nfunction sessionDate(attendance: {\n date: Date;\n event?: { startTime: Date } | null;\n}): Date {\n return attendance.event?.startTime ?? attendance.date;\n}\n\n/** Get attendance for a class (optionally filtered by event). Creates missing records. */\nexport async function getAttendance(classId: string, eventId?: string) {\n const classData = await findClassWithStudents(classId);\n if (!classData) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to view this class's attendance\",\n });\n }\n\n const events = await findEventsByClassId(classId);\n const studentIds = classData.students.map((s) => s.id);\n\n for (const event of events) {\n const existing = await findAttendanceByEventId(event.id);\n if (!existing) {\n const locks =\n classData.schoolId && studentIds.length > 0\n ? buildExcusalLocks(\n await findActiveExcusalsForStudents({\n schoolId: classData.schoolId,\n studentIds,\n date: event.startTime,\n }),\n studentIds\n )\n : [];\n\n const merged = mergeAttendanceUpdateWithLocks({\n present: classData.students.map((s) => ({\n id: s.id,\n username: s.username,\n })),\n late: [],\n absent: [],\n locks,\n });\n\n await createAttendanceForEvent({\n classId,\n eventId: event.id,\n date: event.startTime,\n presentIds: merged.presentIds,\n lateIds: merged.lateIds,\n absentIds: merged.absentIds,\n excusedIds: merged.excusedIds,\n records: merged.records,\n });\n } else if (classData.schoolId && studentIds.length > 0) {\n // Ensure active excusals are reflected on existing sessions.\n const locks = buildExcusalLocks(\n await findActiveExcusalsForStudents({\n schoolId: classData.schoolId,\n studentIds,\n date: event.startTime,\n }),\n studentIds\n );\n const needsLock = locks.filter((lock) => {\n const current = existing.records.find((r) => r.studentId === lock.studentId);\n return !(\n current?.status === \"EXCUSED\" &&\n current.excusedByExcusalId === lock.excusalId\n );\n });\n const byExcusal = new Map<string, string[]>();\n for (const lock of needsLock) {\n const list = byExcusal.get(lock.excusalId) ?? [];\n list.push(lock.studentId);\n byExcusal.set(lock.excusalId, list);\n }\n for (const [excusalId, lockedStudentIds] of byExcusal) {\n await applyExcusalToAttendance({\n schoolId: classData.schoolId,\n excusalId,\n studentIds: lockedStudentIds,\n startDate: event.startTime,\n endDate: event.startTime,\n });\n }\n }\n }\n\n const sessions = await findManyAttendance(classId, eventId);\n return sessions.map(shapeAttendanceSession);\n}\n\n/** Additive shape: keep present/late/absent; expose excused + lock metadata for UI. */\nfunction shapeAttendanceSession<\n T extends {\n records: Array<{\n id: string;\n studentId: string;\n status: string;\n note: string | null;\n excusedByExcusalId: string | null;\n updatedById: string | null;\n updatedAt: Date;\n student: { id: string; username: string };\n excusedByExcusal: {\n id: string;\n reason: string;\n note: string | null;\n } | null;\n }>;\n present: unknown[];\n late: unknown[];\n absent: unknown[];\n },\n>(session: T) {\n const records = session.records.map((r) => ({\n ...r,\n lockedFromExcusal: Boolean(r.excusedByExcusalId),\n reason: r.excusedByExcusal?.reason ?? null,\n excusalNote: r.excusedByExcusal?.note ?? null,\n }));\n const excused = records\n .filter((r) => r.status === \"EXCUSED\")\n .map((r) => r.student);\n\n return {\n ...session,\n excused,\n records,\n };\n}\n\n/** Update attendance record (present/late/absent/excused). Teacher-only. */\nexport async function updateAttendanceRecord(\n userId: string,\n classId: string,\n eventId: string | null | undefined,\n attendance: {\n present: StudentRef[];\n late: StudentRef[];\n absent: StudentRef[];\n excused?: StudentRef[];\n }\n) {\n const classData = await findClassWithTeacher(classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to update this class's attendance\",\n });\n }\n\n const existing = await findAttendanceByClassAndEvent(classId, eventId ?? null);\n const dateForExcusal = existing\n ? sessionDate(existing)\n : new Date();\n\n const classStudentIds = classData.students.map((s) => s.id);\n const locks =\n classData.schoolId && classStudentIds.length > 0\n ? buildExcusalLocks(\n await findActiveExcusalsForStudents({\n schoolId: classData.schoolId,\n studentIds: classStudentIds,\n date: dateForExcusal,\n }),\n classStudentIds\n )\n : [];\n\n const existingNotes = new Map(\n (existing?.records ?? []).map((r) => [r.studentId, r.note])\n );\n\n const merged = mergeAttendanceUpdateWithLocks({\n present: attendance.present,\n late: attendance.late,\n absent: attendance.absent,\n excused: attendance.excused,\n locks,\n updatedById: userId,\n existingNotesByStudentId: existingNotes,\n });\n\n const previousLateIds = new Set(existing?.late.map((student) => student.id) ?? []);\n const previousAbsentIds = new Set(\n existing?.absent.map((student) => student.id) ?? []\n );\n const classStudentIdSet = new Set(classStudentIds);\n\n if (!existing) {\n const created = await createAttendance({\n classId,\n eventId: eventId ?? null,\n presentIds: merged.presentIds,\n lateIds: merged.lateIds,\n absentIds: merged.absentIds,\n excusedIds: merged.excusedIds,\n records: merged.records,\n updatedById: userId,\n });\n await notifyMarkedLateOrAbsent({\n classId,\n className: classData.name,\n eventId: eventId ?? null,\n eventName: created.event?.name ?? null,\n classStudentIds: classStudentIdSet,\n lateIds: merged.lateIds,\n absentIds: merged.absentIds,\n previousLateIds,\n previousAbsentIds,\n });\n return shapeAttendanceSession(created);\n }\n\n const updated = await updateAttendance(existing.id, {\n presentIds: merged.presentIds,\n lateIds: merged.lateIds,\n absentIds: merged.absentIds,\n records: merged.records,\n });\n await notifyMarkedLateOrAbsent({\n classId,\n className: classData.name,\n eventId: eventId ?? null,\n eventName: existing.event?.name ?? null,\n classStudentIds: classStudentIdSet,\n lateIds: merged.lateIds,\n absentIds: merged.absentIds,\n previousLateIds,\n previousAbsentIds,\n });\n return shapeAttendanceSession(updated);\n}\n\n/**\n * School-admin: today's attendance rollup across classes.\n * `percentage` is session-weighted (share of attended class-session records),\n * not a share of `totalStudents`; a student in six classes contributes six records.\n */\nexport async function listTodayAttendanceSummary(\n userId: string,\n schoolId: string\n) {\n await requireSchoolAdmin(schoolId, userId);\n\n const today = new Date();\n const sessions = await listTodaySchoolAttendanceSessions(schoolId, today);\n const memberships = await listSchoolStudentMemberships(schoolId);\n const totalStudents = memberships.length;\n\n const counts = emptyAttendanceCounts();\n const rows: Array<{\n attendanceId: string;\n classId: string;\n className: string;\n section: string;\n subject: string;\n eventId: string | null;\n eventName: string | null;\n date: Date;\n present: number;\n late: number;\n absent: number;\n excused: number;\n unmarked: number;\n classStudentCount: number;\n }> = [];\n\n for (const session of sessions) {\n const tallied = tallyAttendanceStatuses(session.records.map((r) => r.status));\n counts.present += tallied.present;\n counts.late += tallied.late;\n counts.absent += tallied.absent;\n counts.excused += tallied.excused;\n const classStudentCount = session.class._count.students;\n const marked =\n tallied.present + tallied.late + tallied.absent + tallied.excused;\n rows.push({\n attendanceId: session.id,\n classId: session.classId,\n className: session.class.name,\n section: session.class.section,\n subject: session.class.subject,\n eventId: session.eventId,\n eventName: session.event?.name ?? null,\n date: session.event?.startTime ?? session.date,\n present: tallied.present,\n late: tallied.late,\n absent: tallied.absent,\n excused: tallied.excused,\n unmarked: Math.max(0, classStudentCount - marked),\n classStudentCount,\n });\n }\n\n return {\n date: toDateOnly(today),\n totalStudents,\n totals: counts,\n percentage: computeAttendancePercentage(counts),\n sessions: rows,\n };\n}\n\n/** School-admin: per-student attendance counts + % (excused excluded from %). */\nexport async function listStudentAttendanceStats(\n userId: string,\n input: {\n schoolId: string;\n from?: Date;\n to?: Date;\n studentId?: string;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n const memberships = await listSchoolStudentMemberships(input.schoolId);\n const filtered = input.studentId\n ? memberships.filter((m) => m.userId === input.studentId)\n : memberships;\n const studentIds = filtered.map((m) => m.userId);\n\n const records = await listAttendanceRecordsForSchoolStudents({\n schoolId: input.schoolId,\n studentIds,\n from: input.from,\n to: input.to,\n });\n\n const byStudent = new Map<string, ReturnType<typeof emptyAttendanceCounts>>();\n for (const id of studentIds) {\n byStudent.set(id, emptyAttendanceCounts());\n }\n for (const record of records) {\n const counts = byStudent.get(record.studentId);\n if (!counts) continue;\n switch (record.status) {\n case \"PRESENT\":\n counts.present += 1;\n break;\n case \"LATE\":\n counts.late += 1;\n break;\n case \"ABSENT\":\n counts.absent += 1;\n break;\n case \"EXCUSED\":\n counts.excused += 1;\n break;\n default:\n break;\n }\n }\n\n return filtered.map((membership) => {\n const counts = byStudent.get(membership.userId) ?? emptyAttendanceCounts();\n return {\n studentId: membership.userId,\n username: membership.user.username,\n displayName: membership.user.profile?.displayName ?? null,\n profilePicture: membership.user.profile?.profilePicture ?? null,\n profilePictureThumbnail:\n membership.user.profile?.profilePictureThumbnail ?? null,\n classes: membership.user.studentIn,\n present: counts.present,\n late: counts.late,\n absent: counts.absent,\n excused: counts.excused,\n attendancePercentage: computeAttendancePercentage(counts),\n };\n });\n}\n\nexport async function listExcusals(\n userId: string,\n input: {\n schoolId: string;\n includeRevoked?: boolean;\n studentId?: string;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n const excusals = await listExcusalsForSchool(input);\n const now = toDateOnly(new Date());\n\n return excusals.map((excusal) => {\n let status: \"ACTIVE\" | \"UPCOMING\" | \"EXPIRED\" | \"REVOKED\" = \"ACTIVE\";\n if (excusal.revokedAt) {\n status = \"REVOKED\";\n } else if (toDateOnly(excusal.startDate) > now) {\n status = \"UPCOMING\";\n } else if (toDateOnly(excusal.endDate) < now) {\n status = \"EXPIRED\";\n }\n\n return {\n id: excusal.id,\n schoolId: excusal.schoolId,\n startDate: excusal.startDate,\n endDate: excusal.endDate,\n reason: excusal.reason,\n note: excusal.note,\n revokedAt: excusal.revokedAt,\n createdAt: excusal.createdAt,\n updatedAt: excusal.updatedAt,\n status,\n studentIds: excusal.students.map((s) => s.studentId),\n students: excusal.students.map((s) => ({\n id: s.student.id,\n username: s.student.username,\n displayName: s.student.profile?.displayName ?? null,\n profilePicture: s.student.profile?.profilePicture ?? null,\n profilePictureThumbnail:\n s.student.profile?.profilePictureThumbnail ?? null,\n })),\n createdBy: {\n id: excusal.createdBy.id,\n username: excusal.createdBy.username,\n displayName: excusal.createdBy.profile?.displayName ?? null,\n },\n revokedBy: excusal.revokedBy\n ? {\n id: excusal.revokedBy.id,\n username: excusal.revokedBy.username,\n displayName: excusal.revokedBy.profile?.displayName ?? null,\n }\n : null,\n };\n });\n}\n\nexport async function createExcusal(\n userId: string,\n input: {\n schoolId: string;\n studentIds: string[];\n startDate: Date;\n endDate: Date;\n reason: string;\n note?: string | null;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n if (toDateOnly(input.endDate) < toDateOnly(input.startDate)) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"endDate must be on or after startDate\",\n });\n }\n\n const uniqueStudentIds = [...new Set(input.studentIds)];\n const memberships = await listSchoolStudentMemberships(input.schoolId);\n const schoolStudentIds = new Set(memberships.map((m) => m.userId));\n const invalid = uniqueStudentIds.filter((id) => !schoolStudentIds.has(id));\n if (invalid.length > 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"One or more students are not active members of this school\",\n });\n }\n\n const excusal = await createStudentExcusal({\n schoolId: input.schoolId,\n studentIds: uniqueStudentIds,\n startDate: input.startDate,\n endDate: input.endDate,\n reason: input.reason,\n note: input.note,\n createdById: userId,\n });\n\n await applyExcusalToAttendance({\n schoolId: input.schoolId,\n excusalId: excusal.id,\n studentIds: uniqueStudentIds,\n startDate: input.startDate,\n endDate: input.endDate,\n updatedById: userId,\n });\n\n return excusal;\n}\n\nexport async function updateExcusal(\n userId: string,\n input: {\n schoolId: string;\n excusalId: string;\n studentIds?: string[];\n startDate?: Date;\n endDate?: Date;\n reason?: string;\n note?: string | null;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n const existing = await findExcusalById(input.excusalId);\n if (!existing || existing.schoolId !== input.schoolId) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Excusal not found\" });\n }\n if (existing.revokedAt) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot update a revoked excusal\",\n });\n }\n\n const startDate = input.startDate ?? existing.startDate;\n const endDate = input.endDate ?? existing.endDate;\n if (toDateOnly(endDate) < toDateOnly(startDate)) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"endDate must be on or after startDate\",\n });\n }\n\n let studentIds = input.studentIds\n ? [...new Set(input.studentIds)]\n : existing.students.map((s) => s.studentId);\n\n if (input.studentIds) {\n const memberships = await listSchoolStudentMemberships(input.schoolId);\n const schoolStudentIds = new Set(memberships.map((m) => m.userId));\n const invalid = studentIds.filter((id) => !schoolStudentIds.has(id));\n if (invalid.length > 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"One or more students are not active members of this school\",\n });\n }\n }\n\n // Clear previous locks, then re-apply for the new window/students.\n await clearExcusalLocks(input.excusalId);\n\n const updated = await updateStudentExcusal(input.excusalId, {\n studentIds: input.studentIds ? studentIds : undefined,\n startDate: input.startDate,\n endDate: input.endDate,\n reason: input.reason,\n note: input.note,\n });\n\n await applyExcusalToAttendance({\n schoolId: input.schoolId,\n excusalId: updated.id,\n studentIds,\n startDate,\n endDate,\n updatedById: userId,\n });\n\n return updated;\n}\n\nexport async function revokeExcusal(\n userId: string,\n input: { schoolId: string; excusalId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n const existing = await findExcusalById(input.excusalId);\n if (!existing || existing.schoolId !== input.schoolId) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Excusal not found\" });\n }\n if (existing.revokedAt) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Excusal is already revoked\",\n });\n }\n\n await clearExcusalLocks(input.excusalId);\n return revokeStudentExcusal(input.excusalId, userId);\n}\n\n/** Notify only students whose late or absent status is newly added. */\nasync function notifyMarkedLateOrAbsent(input: {\n classId: string;\n className: string;\n eventId: string | null;\n eventName: string | null;\n classStudentIds: Set<string>;\n lateIds: string[];\n absentIds: string[];\n previousLateIds: Set<string>;\n previousAbsentIds: Set<string>;\n}) {\n const lateReceiverIds = [...new Set(input.lateIds)].filter(\n (id) => input.classStudentIds.has(id) && !input.previousLateIds.has(id)\n );\n const absentReceiverIds = [...new Set(input.absentIds)].filter(\n (id) => input.classStudentIds.has(id) && !input.previousAbsentIds.has(id)\n );\n const link = input.eventId\n ? `/class/${input.classId}/attendance/${input.eventId}`\n : `/class/${input.classId}/attendance`;\n const attendanceLabel = input.eventName\n ? `\"${input.eventName}\" in ${input.className}`\n : input.className;\n\n await Promise.all([\n sendAttendanceNotification({\n receiverIds: lateReceiverIds,\n title: `Marked late in ${input.className}`,\n content: `You were marked late for ${attendanceLabel}.\\n[View attendance](${link})`,\n type: \"ATTENDANCE\",\n entityType: \"ATTENDANCE\",\n entityId: input.eventId,\n classId: input.classId,\n }),\n sendAttendanceNotification({\n receiverIds: absentReceiverIds,\n title: `Marked absent in ${input.className}`,\n content: `You were marked absent for ${attendanceLabel}.\\n[View attendance](${link})`,\n type: \"ATTENDANCE\",\n entityType: \"ATTENDANCE\",\n entityId: input.eventId,\n classId: input.classId,\n }),\n ]);\n}\n\n/** Send attendance notifications without failing the attendance update itself. */\nasync function sendAttendanceNotification(input: {\n receiverIds: string[];\n title: string;\n content: string;\n type: \"ATTENDANCE\";\n entityType: string;\n entityId: string | null;\n classId: string;\n}) {\n if (input.receiverIds.length === 0) {\n return;\n }\n\n try {\n await sendToMultiple(input);\n } catch (error) {\n logger.error(\"Failed to send attendance notifications:\", { error });\n }\n}\n\n// Re-export date helpers used by callers/tests.\nexport { toDateOnly, startOfUtcDay, endOfUtcDay };\n"],"names":[],"mappings":"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","debug_id":"a0baad8d-f286-5756-9dfd-397505318152"}
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Class service – CRUD for classes, members, grades, mark schemes, grading boundaries,
3
+ * syllabus, lab drafts, and invite codes.
4
+ */
5
+ import { Prisma } from "@prisma/client";
1
6
  import { Class, Folder } from "@prisma/client";
2
7
  /** Get all classes where user is teacher or student, with assignments and members. */
3
8
  export declare function getAllClasses(userId: string): Promise<{
@@ -226,7 +231,7 @@ export declare function getClass(userId: string, classId: string): Promise<{
226
231
  discussionsEnabled: boolean;
227
232
  studentsCanCreateDiscussions: boolean;
228
233
  studentsCanReply: boolean;
229
- sidebarFeatures: import("@prisma/client/runtime/library.js").JsonValue | null;
234
+ sidebarFeatures: Prisma.JsonValue | null;
230
235
  treatMissingAsZero: boolean;
231
236
  gradeRoundingMode: import(".prisma/client").$Enums.GradeRoundingMode;
232
237
  };
@@ -256,7 +261,7 @@ export declare function updateClass(classId: string, data: {
256
261
  discussionsEnabled: boolean;
257
262
  studentsCanCreateDiscussions: boolean;
258
263
  studentsCanReply: boolean;
259
- sidebarFeatures: import("@prisma/client/runtime/library.js").JsonValue | null;
264
+ sidebarFeatures: Prisma.JsonValue | null;
260
265
  treatMissingAsZero: boolean;
261
266
  gradeRoundingMode: import(".prisma/client").$Enums.GradeRoundingMode;
262
267
  };
@@ -305,7 +310,7 @@ export declare function createClass(userId: string, input: {
305
310
  discussionsEnabled: boolean;
306
311
  studentsCanCreateDiscussions: boolean;
307
312
  studentsCanReply: boolean;
308
- sidebarFeatures: import("@prisma/client/runtime/library.js").JsonValue | null;
313
+ sidebarFeatures: Prisma.JsonValue | null;
309
314
  treatMissingAsZero: boolean;
310
315
  gradeRoundingMode: import(".prisma/client").$Enums.GradeRoundingMode;
311
316
  }>;
@@ -340,7 +345,7 @@ export declare function changeRole(classId: string, userId: string, type: "teach
340
345
  discussionsEnabled: boolean;
341
346
  studentsCanCreateDiscussions: boolean;
342
347
  studentsCanReply: boolean;
343
- sidebarFeatures: import("@prisma/client/runtime/library.js").JsonValue | null;
348
+ sidebarFeatures: Prisma.JsonValue | null;
344
349
  treatMissingAsZero: boolean;
345
350
  gradeRoundingMode: import(".prisma/client").$Enums.GradeRoundingMode;
346
351
  };
@@ -364,7 +369,7 @@ export declare function removeMember(classId: string, userId: string): Promise<{
364
369
  discussionsEnabled: boolean;
365
370
  studentsCanCreateDiscussions: boolean;
366
371
  studentsCanReply: boolean;
367
- sidebarFeatures: import("@prisma/client/runtime/library.js").JsonValue | null;
372
+ sidebarFeatures: Prisma.JsonValue | null;
368
373
  treatMissingAsZero: boolean;
369
374
  gradeRoundingMode: import(".prisma/client").$Enums.GradeRoundingMode;
370
375
  };
@@ -539,7 +544,7 @@ export declare function updateSyllabus(classId: string, contents: string): Promi
539
544
  discussionsEnabled: boolean;
540
545
  studentsCanCreateDiscussions: boolean;
541
546
  studentsCanReply: boolean;
542
- sidebarFeatures: import("@prisma/client/runtime/library.js").JsonValue | null;
547
+ sidebarFeatures: Prisma.JsonValue | null;
543
548
  treatMissingAsZero: boolean;
544
549
  gradeRoundingMode: import(".prisma/client").$Enums.GradeRoundingMode;
545
550
  }>;
@@ -814,8 +819,8 @@ export declare function exportClass(classId: string, userId: string): Promise<{
814
819
  classId: string;
815
820
  questions: {
816
821
  type: import(".prisma/client").$Enums.WorksheetQuestionType;
817
- options: import("@prisma/client/runtime/library.js").JsonValue;
818
- markScheme: import("@prisma/client/runtime/library.js").JsonValue;
822
+ options: Prisma.JsonValue;
823
+ markScheme: Prisma.JsonValue;
819
824
  points: number;
820
825
  question: string;
821
826
  worksheetId: string;
@@ -845,7 +850,7 @@ export declare function exportClass(classId: string, userId: string): Promise<{
845
850
  discussionsEnabled: boolean;
846
851
  studentsCanCreateDiscussions: boolean;
847
852
  studentsCanReply: boolean;
848
- sidebarFeatures: import("@prisma/client/runtime/library.js").JsonValue | null;
853
+ sidebarFeatures: Prisma.JsonValue | null;
849
854
  treatMissingAsZero: boolean;
850
855
  gradeRoundingMode: import(".prisma/client").$Enums.GradeRoundingMode;
851
856
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"class.d.ts","sourceRoot":"/","sources":["services/class.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"class.d.ts","sourceRoot":"/","sources":["services/class.ts"],"names":[],"mappings":"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"}
@@ -3,8 +3,8 @@
3
3
  * syllabus, lab drafts, and invite codes.
4
4
  */
5
5
 
6
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6ff53d14-571e-52bf-9cfe-dd4a7758c1d0")}catch(e){}}();
7
- import { SessionType } from "@prisma/client";
6
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="838e82cf-2053-5dee-a9f1-bc5d20761f0d")}catch(e){}}();
7
+ import { Prisma, SessionType } from "@prisma/client";
8
8
  import { TRPCError } from "@trpc/server";
9
9
  import { prisma } from "../lib/prisma.js";
10
10
  import { generateInviteCode } from "../utils/generateInviteCode.js";
@@ -193,7 +193,7 @@ export async function updateClass(classId, data) {
193
193
  studentsCanReply: data.studentsCanReply,
194
194
  }),
195
195
  ...(data.sidebarFeatures !== undefined && {
196
- sidebarFeatures: data.sidebarFeatures,
196
+ sidebarFeatures: data.sidebarFeatures ?? Prisma.DbNull,
197
197
  }),
198
198
  },
199
199
  select: {
@@ -678,4 +678,4 @@ export async function importClass(classId, userId, year, classData) {
678
678
  }
679
679
  }
680
680
  //# sourceMappingURL=class.js.map
681
- //# debugId=6ff53d14-571e-52bf-9cfe-dd4a7758c1d0
681
+ //# debugId=838e82cf-2053-5dee-a9f1-bc5d20761f0d