Skip to content

Commit ed7e11f

Browse files
Merge pull request #114 from TritonSE/benjaminJohnson2204/final-bug-fixes
Several bugfixes
2 parents 49a4909 + fe99f24 commit ed7e11f

File tree

7 files changed

+99
-50
lines changed

7 files changed

+99
-50
lines changed

backend/src/controllers/student.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import { RequestHandler } from "express";
77
import { validationResult } from "express-validator";
88
import mongoose, { HydratedDocument } from "mongoose";
99

10+
import { ValidationError } from "../errors/validation";
1011
import EnrollmentModel from "../models/enrollment";
1112
import { Image } from "../models/image";
1213
import ProgramModel from "../models/program";
1314
import ProgressNoteModel from "../models/progressNote";
1415
import StudentModel from "../models/student";
16+
import UserModel from "../models/user";
1517
import { Enrollment } from "../types/enrollment";
1618
import { createEnrollment, editEnrollment } from "../util/enrollment";
1719
import validationErrorParser from "../util/validationErrorParser";
@@ -25,14 +27,12 @@ export const createStudent: RequestHandler = async (req, res, next) => {
2527

2628
validationErrorParser(errors);
2729

28-
const newStudentId = new mongoose.Types.ObjectId();
29-
3030
const { enrollments, ...studentData } = req.body as StudentRequest;
3131

3232
// create enrollments for the student
3333
const createdEnrollments = await Promise.all(
3434
enrollments.map(async (program: Enrollment) => {
35-
return await EnrollmentModel.create({ ...program, studentId: newStudentId });
35+
return await EnrollmentModel.create({ ...program, studentId: studentData._id });
3636
}),
3737
);
3838

@@ -51,6 +51,17 @@ export const createStudent: RequestHandler = async (req, res, next) => {
5151

5252
export const editStudent: RequestHandler = async (req, res, next) => {
5353
try {
54+
const { uid } = req.body;
55+
56+
const user = await UserModel.findById(uid);
57+
if (!user) {
58+
throw ValidationError.USER_NOT_FOUND;
59+
}
60+
61+
if (user.accountType !== "admin") {
62+
throw ValidationError.UNAUTHORIZED_USER;
63+
}
64+
5465
const errors = validationResult(req);
5566

5667
validationErrorParser(errors);

backend/src/util/student.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ export const programValidatorUtil = async (enrollments: Enrollment[]) => {
1717

1818
enrollments.forEach((enrollment: Enrollment) => {
1919
requiredFields.forEach((field) => {
20-
if (!enrollment[field as keyof Enrollment])
20+
// Can't just test for truthiness because 0 is a valid value for hoursLeft
21+
if (
22+
enrollment[field as keyof Enrollment] === undefined ||
23+
enrollment[field as keyof Enrollment] === null
24+
)
2125
throw new Error(`Field ${field} is required on enrollment`);
2226
});
2327
});

frontend/src/components/AttendanceTable.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Dot } from "lucide-react";
22
import Image from "next/image";
3-
import React, { Dispatch, SetStateAction, useRef, useState } from "react";
3+
import React, { Dispatch, SetStateAction, useMemo, useRef, useState } from "react";
44
import { FieldValues, SubmitHandler, useForm } from "react-hook-form";
55

66
import { cn } from "../lib/utils";
@@ -33,6 +33,12 @@ export function AttendanceTable({
3333
setRemainingAbsenceSessions,
3434
firebaseToken,
3535
}: TableProps) {
36+
// Exclude students that are not in the session students map for some reason
37+
const existingStudents = useMemo(
38+
() => session.students.filter(({ studentId }) => students[studentId]),
39+
[session.students, students],
40+
);
41+
3642
const {
3743
register,
3844
setValue,
@@ -71,7 +77,7 @@ export function AttendanceTable({
7177
const onSubmit: SubmitHandler<FieldValues> = (data) => {
7278
if (clickedRef.current) return;
7379
clickedRef.current = true;
74-
const studentInfo = session.students.map((student) => {
80+
const studentInfo = existingStudents.map((student) => {
7581
return {
7682
studentId: student.studentId,
7783
attended: data["attended_" + student.studentId] === "true" ? true : false,
@@ -143,12 +149,12 @@ export function AttendanceTable({
143149
</h1>
144150
</div>
145151
<div className="mb-8 grid w-full overflow-x-auto text-left text-sm lg:grid-cols-2 rtl:text-right">
146-
{session.students.map((student, index) => {
152+
{existingStudents.map((student, index) => {
147153
return (
148154
<div
149155
className={cn(
150156
"mr-5 flex grid grid-cols-3 bg-white",
151-
index < session.students.length - (2 - (session.students.length % 2)) &&
157+
index < existingStudents.length - (2 - (existingStudents.length % 2)) &&
152158
"border-b",
153159
index % 2 === 0 ? "ml-5" : "ml-5 lg:ml-10",
154160
)}

frontend/src/components/StudentForm/EnrollmentsEdit.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,11 @@ const EnrollmentFormItem = ({
182182

183183
let totalHours = 0;
184184

185-
for (let d = new Date(startDate); d <= new Date(endDate); d.setDate(d.getDate() + 1)) {
186-
if (days.includes(d.toLocaleString("en-US", { weekday: "long" }))) {
187-
totalHours += sessionLength;
185+
if (!isNaN(sessionLength)) {
186+
for (let d = new Date(startDate); d <= new Date(endDate); d.setDate(d.getDate() + 1)) {
187+
if (days.includes(d.toLocaleString("en-US", { weekday: "long" }))) {
188+
totalHours += sessionLength;
189+
}
188190
}
189191
}
190192
console.log(totalHours);

frontend/src/components/StudentProfile.tsx

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -309,27 +309,50 @@ export default function StudentProfile({ id }: StudentProfileProps) {
309309
<div id="top" className="flex justify-between">
310310
<ArrowHome />
311311
{/*no need to set all students*/}
312-
<button
313-
className="flex cursor-pointer space-x-[5px]"
314-
type="button"
315-
onClick={() => {
316-
handleViewChange();
317-
}}
318-
>
319-
<svg
320-
width="20"
321-
height="22"
322-
viewBox="0 0 10 11"
323-
fill="none"
324-
xmlns="http://www.w3.org/2000/svg"
312+
{isAdmin ? (
313+
<button
314+
className="flex cursor-pointer space-x-[5px]"
315+
type="button"
316+
onClick={() => {
317+
handleViewChange();
318+
}}
325319
>
326-
<path
327-
d="M9.02645 1.38024C8.86568 1.21944 8.67481 1.09189 8.46475 1.00486C8.25468 0.917838 8.02953 0.873047 7.80215 0.873047C7.57477 0.873047 7.34962 0.917838 7.13955 1.00486C6.92948 1.09189 6.73861 1.21944 6.57785 1.38024L1.37812 6.57996C1.13117 6.82707 0.955067 7.13594 0.868192 7.47432L0.293527 9.71089C0.279277 9.76654 0.279787 9.82494 0.295008 9.88033C0.310229 9.93573 0.339634 9.98619 0.38032 10.0267C0.421006 10.0673 0.471565 10.0965 0.527006 10.1116C0.582447 10.1266 0.640852 10.1269 0.696453 10.1125L2.93236 9.53849C3.27081 9.45177 3.57971 9.27564 3.82672 9.02856L9.02645 3.82884C9.18724 3.66807 9.3148 3.4772 9.40182 3.26713C9.48884 3.05707 9.53364 2.83191 9.53364 2.60454C9.53364 2.37716 9.48884 2.152 9.40182 1.94194C9.3148 1.73187 9.18724 1.541 9.02645 1.38024ZM7.04485 1.84723C7.24569 1.64638 7.5181 1.53355 7.80215 1.53355C8.08619 1.53355 8.3586 1.64638 8.55945 1.84723C8.7603 2.04808 8.87313 2.32049 8.87313 2.60454C8.87313 2.88858 8.7603 3.16099 8.55945 3.36184L8.04489 3.87639L6.53029 2.36179L7.04485 1.84723ZM6.06329 2.82879L7.5779 4.34339L3.35973 8.56156C3.19616 8.72481 2.99177 8.84115 2.76789 8.89843L1.0723 9.33439L1.50825 7.6388C1.56511 7.41474 1.68151 7.21024 1.84512 7.04696L6.06329 2.82879Z"
328-
fill="black"
329-
/>
330-
</svg>
331-
<div>{currentView === "Edit" ? "View" : "Edit"} Mode</div>
332-
</button>
320+
<svg
321+
width="20"
322+
height="22"
323+
viewBox="0 0 10 11"
324+
fill="none"
325+
xmlns="http://www.w3.org/2000/svg"
326+
>
327+
<path
328+
d="M9.02645 1.38024C8.86568 1.21944 8.67481 1.09189 8.46475 1.00486C8.25468 0.917838 8.02953 0.873047 7.80215 0.873047C7.57477 0.873047 7.34962 0.917838 7.13955 1.00486C6.92948 1.09189 6.73861 1.21944 6.57785 1.38024L1.37812 6.57996C1.13117 6.82707 0.955067 7.13594 0.868192 7.47432L0.293527 9.71089C0.279277 9.76654 0.279787 9.82494 0.295008 9.88033C0.310229 9.93573 0.339634 9.98619 0.38032 10.0267C0.421006 10.0673 0.471565 10.0965 0.527006 10.1116C0.582447 10.1266 0.640852 10.1269 0.696453 10.1125L2.93236 9.53849C3.27081 9.45177 3.57971 9.27564 3.82672 9.02856L9.02645 3.82884C9.18724 3.66807 9.3148 3.4772 9.40182 3.26713C9.48884 3.05707 9.53364 2.83191 9.53364 2.60454C9.53364 2.37716 9.48884 2.152 9.40182 1.94194C9.3148 1.73187 9.18724 1.541 9.02645 1.38024ZM7.04485 1.84723C7.24569 1.64638 7.5181 1.53355 7.80215 1.53355C8.08619 1.53355 8.3586 1.64638 8.55945 1.84723C8.7603 2.04808 8.87313 2.32049 8.87313 2.60454C8.87313 2.88858 8.7603 3.16099 8.55945 3.36184L8.04489 3.87639L6.53029 2.36179L7.04485 1.84723ZM6.06329 2.82879L7.5779 4.34339L3.35973 8.56156C3.19616 8.72481 2.99177 8.84115 2.76789 8.89843L1.0723 9.33439L1.50825 7.6388C1.56511 7.41474 1.68151 7.21024 1.84512 7.04696L6.06329 2.82879Z"
329+
fill="black"
330+
/>
331+
</svg>
332+
<div>{currentView === "Edit" ? "View" : "Edit"} Mode</div>
333+
</button>
334+
) : (
335+
<button
336+
className="flex cursor-pointer space-x-[5px]"
337+
type="button"
338+
disabled
339+
style={{ cursor: "unset" }}
340+
>
341+
<svg
342+
width="20"
343+
height="22"
344+
viewBox="0 0 10 11"
345+
fill="none"
346+
xmlns="http://www.w3.org/2000/svg"
347+
>
348+
<path
349+
d="M9.02645 1.38024C8.86568 1.21944 8.67481 1.09189 8.46475 1.00486C8.25468 0.917838 8.02953 0.873047 7.80215 0.873047C7.57477 0.873047 7.34962 0.917838 7.13955 1.00486C6.92948 1.09189 6.73861 1.21944 6.57785 1.38024L1.37812 6.57996C1.13117 6.82707 0.955067 7.13594 0.868192 7.47432L0.293527 9.71089C0.279277 9.76654 0.279787 9.82494 0.295008 9.88033C0.310229 9.93573 0.339634 9.98619 0.38032 10.0267C0.421006 10.0673 0.471565 10.0965 0.527006 10.1116C0.582447 10.1266 0.640852 10.1269 0.696453 10.1125L2.93236 9.53849C3.27081 9.45177 3.57971 9.27564 3.82672 9.02856L9.02645 3.82884C9.18724 3.66807 9.3148 3.4772 9.40182 3.26713C9.48884 3.05707 9.53364 2.83191 9.53364 2.60454C9.53364 2.37716 9.48884 2.152 9.40182 1.94194C9.3148 1.73187 9.18724 1.541 9.02645 1.38024ZM7.04485 1.84723C7.24569 1.64638 7.5181 1.53355 7.80215 1.53355C8.08619 1.53355 8.3586 1.64638 8.55945 1.84723C8.7603 2.04808 8.87313 2.32049 8.87313 2.60454C8.87313 2.88858 8.7603 3.16099 8.55945 3.36184L8.04489 3.87639L6.53029 2.36179L7.04485 1.84723ZM6.06329 2.82879L7.5779 4.34339L3.35973 8.56156C3.19616 8.72481 2.99177 8.84115 2.76789 8.89843L1.0723 9.33439L1.50825 7.6388C1.56511 7.41474 1.68151 7.21024 1.84512 7.04696L6.06329 2.82879Z"
350+
fill="black"
351+
/>
352+
</svg>
353+
<div>{currentView === "Edit" ? "View" : "Edit"} Mode</div>
354+
</button>
355+
)}
333356
</div>
334357

335358
{currentView === "View" ? (

frontend/src/components/StudentsTable/useColumnSchema.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Link from "next/link";
44
import { useMemo } from "react";
55

66
import { Popover, PopoverContent, PopoverTrigger } from "../../components/ui/popover";
7-
import { Contact, Enrollment, ProgramLink } from "../StudentForm/types";
7+
import { Contact, Enrollment } from "../StudentForm/types";
88

99
import { Columns, ProgramMap, StudentMap } from "./types";
1010

@@ -38,13 +38,13 @@ const PopoverInfoRow = ({ label, value }: { label: string; value: string }) => (
3838
</span>
3939
);
4040

41-
const ProgramPopover = ({ link, program }: { link: ProgramLink; program: Program }) => {
41+
const ProgramPopover = ({ link, program }: { link: Enrollment; program: Program }) => {
4242
if (!program) return null;
4343
const rowInfo = [
4444
["Type", program.type],
4545
["Schedule", program.daysOfWeek.join(", ")],
46-
["Start Date", new Date(/*program.startDate*/).toLocaleDateString("en-US")],
47-
["Renewal Date", new Date(/*program.endDate*/).toLocaleDateString("en-US")],
46+
["Start Date", new Date(link.startDate).toLocaleDateString("en-US")],
47+
["Renewal Date", new Date(link.renewalDate).toLocaleDateString("en-US")],
4848
["Hours Left", link.hoursLeft.toString()],
4949
];
5050

@@ -127,7 +127,7 @@ export function useColumnSchema({
127127
id: isTablet ? "Curr. P1" : "Curr. Program 1",
128128
header: isTablet ? "Curr. P1" : "Curr. Program 1",
129129
cell: (info) => {
130-
const enrollments = info.getValue() as unknown as ProgramLink[];
130+
const enrollments = info.getValue() as unknown as Enrollment[];
131131
const link = enrollments.filter((enr) => enr.status === "Joined")[0];
132132
if (!link) return null;
133133
const program = allPrograms[link.programId];
@@ -140,7 +140,7 @@ export function useColumnSchema({
140140
id: isTablet ? "Curr. P2" : "Curr. Program 2",
141141
header: isTablet ? "Curr. P2" : "Curr. Program 2",
142142
cell: (info) => {
143-
const enrollments = info.getValue() as unknown as ProgramLink[];
143+
const enrollments = info.getValue() as unknown as Enrollment[];
144144
const link = enrollments.filter((enr) => enr.status === "Joined")[1];
145145
if (!link) return null;
146146
const program = allPrograms[link.programId];

frontend/src/pages/attendance.tsx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -156,19 +156,22 @@ export default function AttendanceDashboard() {
156156
className="flex overflow-x-hidden overflow-y-hidden hover:overflow-x-auto"
157157
ref={scrollRef}
158158
>
159-
{allAbsenceSessions?.map((absenceSession, i) => {
160-
const program = allPrograms[absenceSession.programId];
161-
const student = allStudents[absenceSession.studentId];
162-
return (
163-
<AttendanceCard
164-
program={program}
165-
student={student}
166-
key={i}
167-
setRemainingSessions={setRemainingAbsenceSessions}
168-
firebaseToken={firebaseToken}
169-
/>
170-
);
171-
})}
159+
{// Exclude students that are not in the session students map for some reason
160+
allAbsenceSessions
161+
?.filter((absenceSession) => allStudents[absenceSession.studentId])
162+
.map((absenceSession, i) => {
163+
const program = allPrograms[absenceSession.programId];
164+
const student = allStudents[absenceSession.studentId];
165+
return (
166+
<AttendanceCard
167+
program={program}
168+
student={student}
169+
key={i}
170+
setRemainingSessions={setRemainingAbsenceSessions}
171+
firebaseToken={firebaseToken}
172+
/>
173+
);
174+
})}
172175
{remainingAbsenceSessions === 0 && (
173176
<div className="border-gray flex h-[326px] w-[240px] items-center justify-center rounded-2xl border bg-white">
174177
<div className="ml-5">

0 commit comments

Comments
 (0)