From e489e7ba75ecc8681227584433210e53992d1c9e Mon Sep 17 00:00:00 2001 From: mraysu Date: Thu, 7 Nov 2024 15:37:14 -0800 Subject: [PATCH] Printing Student Profile --- frontend/package-lock.json | 10 ++ frontend/package.json | 1 + frontend/src/components/StudentProfile.tsx | 144 +++++++++--------- .../StudentProfilePrintComponent.tsx | 110 +++++++++++++ 4 files changed, 191 insertions(+), 74 deletions(-) create mode 100644 frontend/src/components/StudentProfilePrintComponent.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5fd73087..6b053bef 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -31,6 +31,7 @@ "react-day-picker": "^8.10.0", "react-dom": "^18", "react-hook-form": "^7.49.3", + "react-to-print": "^3.0.2", "tailwind-merge": "^2.2.0", "tailwindcss": "^3.4.1", "tailwindcss-animate": "^1.0.7", @@ -10130,6 +10131,15 @@ } } }, + "node_modules/react-to-print": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/react-to-print/-/react-to-print-3.0.2.tgz", + "integrity": "sha512-FS/Z4LLq0bgWaxd7obygFQ8yRFdKW74iE8fIVjFFsPJWIXmuL8CIO+4me1Hj44lrlxQ00gscSNb3BRM8olbwXg==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ~19" + } + }, "node_modules/read-cache": { "version": "1.0.0", "license": "MIT", diff --git a/frontend/package.json b/frontend/package.json index 2db45b74..40caa687 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -38,6 +38,7 @@ "react-day-picker": "^8.10.0", "react-dom": "^18", "react-hook-form": "^7.49.3", + "react-to-print": "^3.0.2", "tailwind-merge": "^2.2.0", "tailwindcss": "^3.4.1", "tailwindcss-animate": "^1.0.7", diff --git a/frontend/src/components/StudentProfile.tsx b/frontend/src/components/StudentProfile.tsx index 01356e6c..c2a53736 100644 --- a/frontend/src/components/StudentProfile.tsx +++ b/frontend/src/components/StudentProfile.tsx @@ -1,14 +1,33 @@ import Link from "next/link"; -import { Dispatch, SetStateAction, useContext, useEffect, useState } from "react"; +import { Dispatch, SetStateAction, useContext, useEffect, useRef, useState } from "react"; +import { useReactToPrint } from "react-to-print"; -import { Enrollment, Program } from "../api/programs"; +import { Enrollment } from "../api/programs"; import { Student, getStudent } from "../api/students"; import { ProgramsContext } from "../contexts/program"; import { Contact } from "./StudentForm/types"; import StudentFormButton from "./StudentFormButton"; +import StudentProfilePrintComponent from "./StudentProfilePrintComponent"; import { StudentMap } from "./StudentsTable/types"; +// Aggregate only the fields necessary for display on frontend +// to reduce confusion when managing programs/programlinks/enrollments +export type EnrollmentDisplayInfo = { + name: string; + type: string; + status: string; + abbreviation: string; + startDate: Date; + renewalDate: Date; + authNumber: string; + sessionTime: { + start_time: string; + end_time: string; + }; + schedule: string[]; +}; + type StudentProfileProps = { id: string; }; @@ -20,8 +39,7 @@ type ContactLayoutProps = { }; type ProgramLayoutProps = { - program: Program; - enrollment: Enrollment; + enrollmentInfo: EnrollmentDisplayInfo; }; function formatDate(d: Date) { @@ -56,14 +74,14 @@ function ContactLayout({ contact, header, children }: ContactLayoutProps) { ); } -function ProgramLayout({ program, enrollment }: ProgramLayoutProps) { - const regular = program.type === "regular"; +function ProgramLayout({ enrollmentInfo }: ProgramLayoutProps) { + const regular = enrollmentInfo.type === "regular"; return ( <>
-
{program.abbreviation} -
+
{enrollmentInfo.abbreviation} -
{(() => { - switch (enrollment.status) { + switch (enrollmentInfo.status) { case "Joined": return
Joined
; case "Waitlisted": @@ -78,16 +96,21 @@ function ProgramLayout({ program, enrollment }: ProgramLayoutProps) { })()}
- Start Date: {formatDate(enrollment.startDate)} + Start Date: {formatDate(enrollmentInfo.startDate)} +
+
+ End Date: {formatDate(enrollmentInfo.renewalDate)}
- End Date: {formatDate(enrollment.renewalDate)} + Authorization Code: {enrollmentInfo.authNumber}{" "}
-
Authorization Code: {enrollment.authNumber}
{regular && (
Session Time: - {" " + enrollment.sessionTime.start_time + " - " + enrollment.sessionTime.end_time} + {" " + + enrollmentInfo.sessionTime.start_time + + " - " + + enrollmentInfo.sessionTime.end_time}
)} {regular && ( @@ -96,7 +119,7 @@ function ProgramLayout({ program, enrollment }: ProgramLayoutProps) {
{["M", "T", "W", "Th", "F", "Sa", "Su"].map((value) => { if ( - enrollment.schedule.find((day) => { + enrollmentInfo.schedule.find((day) => { return day === value; }) ) @@ -117,28 +140,6 @@ function ProgramLayout({ program, enrollment }: ProgramLayoutProps) {
); })} - - {/*
-
SU
-
-
-
M
-
-
-
T
-
-
-
W
-
-
-
TH
-
-
-
F
-
-
-
SA
-
*/} )} @@ -146,15 +147,13 @@ function ProgramLayout({ program, enrollment }: ProgramLayoutProps) { ); } -function printProfile(student: students) { - -} - export default function StudentProfile({ id }: StudentProfileProps) { const [notFound, setNotFound] = useState(false); const [studentData, setStudentData] = useState(); - const [programs, setPrograms] = useState(); + const [enrollmentInfo, setEnrollmentInfo] = useState(); const { allPrograms } = useContext(ProgramsContext); + const contentRef = useRef(null); + const reactToPrintFn = useReactToPrint({ contentRef }); useEffect(() => { getStudent(id) @@ -174,13 +173,17 @@ export default function StudentProfile({ id }: StudentProfileProps) { useEffect(() => { if (studentData) { - setPrograms(studentData.programs.map((programLink) => allPrograms[programLink.programId])); + setEnrollmentInfo( + studentData.programs.map((value) => { + return { + ...allPrograms[value.programId], + ...(value as unknown as Enrollment), + }; + }), + ); } }, [studentData]); - if (studentData) console.log(studentData); - if (programs) console.log(programs); - if (notFound) { return (
@@ -191,7 +194,7 @@ export default function StudentProfile({ id }: StudentProfileProps) { } return ( studentData && - programs && ( + enrollmentInfo && (
@@ -202,15 +205,15 @@ export default function StudentProfile({ id }: StudentProfileProps) { setAllStudents={undefined as unknown as Dispatch>} />
-
-
) diff --git a/frontend/src/components/StudentProfilePrintComponent.tsx b/frontend/src/components/StudentProfilePrintComponent.tsx new file mode 100644 index 00000000..a5ebc56f --- /dev/null +++ b/frontend/src/components/StudentProfilePrintComponent.tsx @@ -0,0 +1,110 @@ +import { LegacyRef } from "react"; + +import { Student } from "../api/students"; +import { EnrollmentDisplayInfo } from "./StudentProfile"; + +type PrintComponentProps = { + data: Student; + contentRef: LegacyRef | undefined; + enrollments: EnrollmentDisplayInfo[]; +}; + +type PrintContactProps = { + firstName: string; + lastName: string; + email: string; + phoneNumber: string; + header: string; +}; +type PrintProgramProps = { + enrollmentInfo: EnrollmentDisplayInfo; +}; +function Contact({ firstName, lastName, email, phoneNumber, header }: PrintContactProps) { + return ( +
+

{header}

+

{firstName + " " + lastName}

+

{email}

+

{phoneNumber}

+
+ ); +} + +function Program({ enrollmentInfo }: PrintProgramProps) { + const regular = enrollmentInfo.type === "regular"; + return ( +
+
{enrollmentInfo.name}
+
{enrollmentInfo.abbreviation}
+
Status: {enrollmentInfo.status}
+
Start Date: {formatDate(enrollmentInfo.startDate)}
+
End Date: {formatDate(enrollmentInfo.renewalDate)}
+
Authorization Code: {enrollmentInfo.authNumber}
+ {regular && ( +
+ Session Time: + {" " + + enrollmentInfo.sessionTime.start_time + + " - " + + enrollmentInfo.sessionTime.end_time} +
+ )} + {regular &&
Days of the Week: {enrollmentInfo.schedule.join(", ")}
} +
+ ); +} + +function formatDate(d: Date) { + const date = new Date(d); + return date.getMonth() + 1 + "/" + date.getDate() + "/" + date.getFullYear(); +} + +export default function StudentProfilePrintComponent({ + data, + contentRef, + enrollments, +}: PrintComponentProps) { + return ( +
+
+ + + +
+
Student Background:
+
Address: {data.location}
+
Birthdate: {formatDate(data.birthday)}
+
Student Information:
+
Intake Date: {formatDate(data.intakeDate)}
+
Tour Date: {formatDate(data.tourDate)}
+
Medication & Medical
+
Dietary Restrictions:
+
+ {data.dietary.map((value) => ( +
  • {value}
  • + ))} +
    +
    Medication: {data.medication}
    +
    +
    +
    Regular Programs
    + {enrollments.map((value, index) => { + if (value.type === "regular") { + return ; + } + return <>; + })} +
    +
    +
    Varying Programs
    + {enrollments.map((value, index) => { + if (value.type === "varying") { + return ; + } + return <>; + })} +
    +
    +
    + ); +}