From 435a627da088bc3d112c11effd24a3b02225da8a Mon Sep 17 00:00:00 2001 From: mraysu Date: Wed, 24 Apr 2024 14:08:00 -0700 Subject: [PATCH 01/11] Archive Program Route --- backend/src/controllers/program.ts | 32 ++++++++++++++++++++++++++++++ backend/src/routes/program.ts | 1 + 2 files changed, 33 insertions(+) diff --git a/backend/src/controllers/program.ts b/backend/src/controllers/program.ts index 581f4db2..390fc4f4 100644 --- a/backend/src/controllers/program.ts +++ b/backend/src/controllers/program.ts @@ -5,6 +5,7 @@ import { Schema } from "mongoose"; //import { error } from "firebase-functions/logger"; import ProgramModel from "../models/program"; +import StudentModel from "../models/student"; import validationErrorParser from "../util/validationErrorParser"; export type Program = { @@ -58,6 +59,37 @@ export const updateProgram: RequestHandler = async (req, res, next) => { } }; +export const archiveProgram: RequestHandler = async (req, res, next) => { + const errors = validationResult(req); + try { + validationErrorParser(errors); + + const programID = req.body as Schema.Types.ObjectId; + const program = await ProgramModel.findById(programID); + if (!program) + return res.status(404).json({ message: "Program with this id not found in database" }); + //in case this program doesnt have students field + const studentList = program.students ?? []; + + await Promise.all( + studentList.map(async (studentID) => { + await StudentModel.findByIdAndUpdate( + studentID, + { + $set: { + "programs.$[element].status": "Archived", + "programs.$[element].dateUpdated": Date.now(), + }, + }, + { arrayFilters: [{ "element.id": programID }] }, + ); + }), + ); + } catch (error) { + next(error); + } +}; + export const getAllPrograms: RequestHandler = async (req, res, next) => { try { const programs = await ProgramModel.find(); diff --git a/backend/src/routes/program.ts b/backend/src/routes/program.ts index 05e24645..526deb78 100644 --- a/backend/src/routes/program.ts +++ b/backend/src/routes/program.ts @@ -11,6 +11,7 @@ const router = express.Router(); router.patch("/:id", ProgramValidator.updateProgram, ProgramController.updateProgram); router.post("/create", ProgramValidator.createProgram, ProgramController.createProgram); +router.post("/archive", ProgramController.archiveProgram); router.get("/all", ProgramController.getAllPrograms); export default router; From b2fe97cdb7e60fd00975e75fcf9ea6657c69bec4 Mon Sep 17 00:00:00 2001 From: mraysu Date: Wed, 24 Apr 2024 16:55:34 -0700 Subject: [PATCH 02/11] Change program status to archived for students --- backend/src/controllers/program.ts | 6 ++++-- backend/src/controllers/student.ts | 2 +- backend/src/routes/program.ts | 2 +- frontend/src/pages/home.tsx | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/src/controllers/program.ts b/backend/src/controllers/program.ts index 390fc4f4..7108bf10 100644 --- a/backend/src/controllers/program.ts +++ b/backend/src/controllers/program.ts @@ -64,7 +64,7 @@ export const archiveProgram: RequestHandler = async (req, res, next) => { try { validationErrorParser(errors); - const programID = req.body as Schema.Types.ObjectId; + const programID = req.params.id; const program = await ProgramModel.findById(programID); if (!program) return res.status(404).json({ message: "Program with this id not found in database" }); @@ -81,10 +81,12 @@ export const archiveProgram: RequestHandler = async (req, res, next) => { "programs.$[element].dateUpdated": Date.now(), }, }, - { arrayFilters: [{ "element.id": programID }] }, + { arrayFilters: [{ "element.programId": programID }], new: true }, ); }), ); + + return res.status(200).end(); } catch (error) { next(error); } diff --git a/backend/src/controllers/student.ts b/backend/src/controllers/student.ts index a93056ae..853b9353 100644 --- a/backend/src/controllers/student.ts +++ b/backend/src/controllers/student.ts @@ -39,7 +39,7 @@ type Contact = { phoneNumber: string; }; -type Student = { +export type Student = { _id: string; student: Contact; emergency: Contact; diff --git a/backend/src/routes/program.ts b/backend/src/routes/program.ts index 526deb78..df2af7df 100644 --- a/backend/src/routes/program.ts +++ b/backend/src/routes/program.ts @@ -11,7 +11,7 @@ const router = express.Router(); router.patch("/:id", ProgramValidator.updateProgram, ProgramController.updateProgram); router.post("/create", ProgramValidator.createProgram, ProgramController.createProgram); -router.post("/archive", ProgramController.archiveProgram); +router.post("/archive/:id", ProgramController.archiveProgram); router.get("/all", ProgramController.getAllPrograms); export default router; diff --git a/frontend/src/pages/home.tsx b/frontend/src/pages/home.tsx index 5cf731be..bb132962 100644 --- a/frontend/src/pages/home.tsx +++ b/frontend/src/pages/home.tsx @@ -3,6 +3,6 @@ import StudentsTable from "../components/StudentsTable/StudentsTable"; import { useRedirectToLoginIfNotSignedIn } from "@/hooks/redirect"; export default function Home() { - useRedirectToLoginIfNotSignedIn(); + //useRedirectToLoginIfNotSignedIn(); return ; } From 839a4d097eb7c48ccc1cc0e3ef83670f64ff30fd Mon Sep 17 00:00:00 2001 From: mraysu Date: Wed, 24 Apr 2024 17:04:59 -0700 Subject: [PATCH 03/11] Added Archived field to program schema --- backend/src/controllers/program.ts | 4 +++- backend/src/models/program.ts | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/src/controllers/program.ts b/backend/src/controllers/program.ts index 7108bf10..9c3d552f 100644 --- a/backend/src/controllers/program.ts +++ b/backend/src/controllers/program.ts @@ -21,6 +21,7 @@ export type Program = { renewalDate: Date; hourlyPay: string; sessions: [string[]]; + archived?: boolean; }; export const createProgram: RequestHandler = async (req, res, next) => { @@ -65,9 +66,10 @@ export const archiveProgram: RequestHandler = async (req, res, next) => { validationErrorParser(errors); const programID = req.params.id; - const program = await ProgramModel.findById(programID); + const program = await ProgramModel.findByIdAndUpdate(programID, { $set: { archived: true } }); if (!program) return res.status(404).json({ message: "Program with this id not found in database" }); + //in case this program doesnt have students field const studentList = program.students ?? []; diff --git a/backend/src/models/program.ts b/backend/src/models/program.ts index 7d558e09..ba6488f8 100644 --- a/backend/src/models/program.ts +++ b/backend/src/models/program.ts @@ -12,6 +12,7 @@ const programSchema = new Schema({ renewalDate: { type: Date, required: true }, hourly: { type: Number, required: true }, sessions: { type: [[String]], required: true }, + archived: { type: Boolean, required: false }, }); type Program = InferSchemaType; From 949518f910ab20a8ba41293f26fc61cd4ada2b57 Mon Sep 17 00:00:00 2001 From: mraysu Date: Wed, 24 Apr 2024 17:47:56 -0700 Subject: [PATCH 04/11] Implemented Archive Button --- frontend/src/api/programs.ts | 9 ++ frontend/src/components/ProgramFormButton.tsx | 90 ++++++++++--------- frontend/src/pages/programs.tsx | 4 +- 3 files changed, 58 insertions(+), 45 deletions(-) diff --git a/frontend/src/api/programs.ts b/frontend/src/api/programs.ts index 7bafeda0..5c7a2d92 100644 --- a/frontend/src/api/programs.ts +++ b/frontend/src/api/programs.ts @@ -46,3 +46,12 @@ export async function getAllPrograms(): Promise> { return handleAPIError(error); } } + +export async function archiveProgram(program: Program): Promise> { + try { + await POST(`/program/archive/${program._id}`, undefined); + return { success: true, data: true }; + } catch (error) { + return handleAPIError(error); + } +} diff --git a/frontend/src/components/ProgramFormButton.tsx b/frontend/src/components/ProgramFormButton.tsx index 6be94b75..dc4fbfb0 100644 --- a/frontend/src/components/ProgramFormButton.tsx +++ b/frontend/src/components/ProgramFormButton.tsx @@ -1,8 +1,8 @@ import Image from "next/image"; -import { useMemo, useState } from "react"; +import { MouseEventHandler, useMemo, useState } from "react"; import { SubmitHandler, useForm } from "react-hook-form"; -import { Program, createProgram, editProgram } from "../api/programs"; +import { Program, archiveProgram, createProgram, editProgram } from "../api/programs"; import { useWindowSize } from "../hooks/useWindowSize"; import { cn } from "../lib/utils"; @@ -51,6 +51,39 @@ export default function ProgramFormButton({ const { width } = useWindowSize().windowSize; const isMobile = useMemo(() => width <= 640, [width]); + const archive: MouseEventHandler = () => { + // This function should only call in edit mode, which requires data to exist. + // the following conditional is required to make lint happy + if (!data) { + alert("Illegal archiving of non-existent program"); + return; + } + + const date = new Date(getArchiveValue("date")); + const today = new Date(); + if ( + date.getDate() === today.getDate() && + date.getMonth() === today.getMonth() && + date.getFullYear() === today.getFullYear() + ) { + archiveProgram(data) + .then((result) => { + if (result.success) { + console.log("Archive success"); + archiveReset(); + setOpenArchive(false); + setOpenForm(false); + } else { + console.log(result.error); + alert("Unable to archive program: " + result.error); + } + }) + .catch((error) => { + console.log(error); + }); + } + }; + const onSubmit: SubmitHandler = (formData: ProgramData) => { const sanitizedSessions = formData.sessions ? formData.sessions.filter((session: string[]) => session[0] || session[1]) @@ -144,13 +177,15 @@ export default function ProgramFormButton({
- {/*
@@ -178,24 +213,7 @@ export default function ProgramFormButton({ /> - ); + const selectorWrapper = + "relative sm:m-5 flex grid h-6 sm:min-h-12 w-full sm:w-[256px] grid-cols-2 divide-x border-none pointer-events-auto"; + const selectorClass = "flex h-full w-full items-center justify-center border-none"; + const radioClass = "peer flex h-full w-full appearance-none cursor-pointer"; + const selectorLabel = "absolute pointer-events-none sm:text-lg text-sm text-pia_dark_green"; + return (
@@ -108,6 +116,40 @@ export default function Programs() { )} {/* Should be replaced with Add Button when created */}
+
+
+ { + setSliderOffset(0); + setArchiveView(false); + }} + /> +
Active
+
+
+ { + setSliderOffset(128); + setArchiveView(true); + }} + /> +
Archived
+
+
+
{Object.keys(programs).length === 0 && (
@@ -122,12 +164,16 @@ export default function Programs() {
)} {Object.keys(programs).length > 0 && ( -
- {Object.values(programs).map((program) => ( -
- -
- ))} +
+ {Object.values(programs).map((program) => + program.archived === archiveView || program.archived === undefined ? ( +
+ +
+ ) : ( + <> + ), + )}
)}
From 3f58cfb6949e3df82aba085e2b7b2df1d46a8c7d Mon Sep 17 00:00:00 2001 From: mraysu Date: Fri, 24 May 2024 21:42:44 -0700 Subject: [PATCH 09/11] Fix merge issues --- frontend/src/pages/programs.tsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/frontend/src/pages/programs.tsx b/frontend/src/pages/programs.tsx index 831f2785..eda6f620 100644 --- a/frontend/src/pages/programs.tsx +++ b/frontend/src/pages/programs.tsx @@ -1,5 +1,5 @@ import Image from "next/image"; -import React, { useContext, useMemo } from "react"; +import React, { useContext, useMemo, useState } from "react"; import { ProgramCard } from "../components/ProgramCard"; import ProgramFormButton from "../components/ProgramFormButton"; @@ -18,7 +18,6 @@ export default function Programs() { const isTablet = useMemo(() => windowSize.width < 1024, [windowSize.width]); const extraLarge = useMemo(() => windowSize.width >= 2000, [windowSize.width]); - //const [programs, setPrograms] = useState({}); const [archiveView, setArchiveView] = useState(false); const [sliderOffset, setSliderOffset] = useState(0); @@ -154,12 +153,16 @@ export default function Programs() { )} {Object.keys(programs).length > 0 && ( -
- {Object.values(programs).map((program) => ( -
- -
- ))} +
+ {Object.values(programs).map((program) => + program.archived === archiveView || program.archived === undefined ? ( +
+ +
+ ) : ( + <> + ), + )}
)} From 15dc484fed518f3b20d6121de601bbace715a656 Mon Sep 17 00:00:00 2001 From: mraysu Date: Thu, 30 May 2024 01:33:24 -0700 Subject: [PATCH 10/11] Updated Archive Page View --- backend/src/controllers/program.ts | 30 ++++++++---- backend/src/models/program.ts | 4 +- frontend/src/api/programs.ts | 2 +- frontend/src/components/AlertCard.tsx | 35 ++++++++++++++ frontend/src/components/ProgramCard.tsx | 47 +++++++++++++++---- .../components/ProgramForm/ProgramArchive.tsx | 18 ++++++- frontend/src/components/ProgramForm/types.ts | 1 + frontend/src/components/ProgramFormButton.tsx | 27 +++++++++-- frontend/src/pages/programs.tsx | 28 ++++++++++- 9 files changed, 165 insertions(+), 27 deletions(-) create mode 100644 frontend/src/components/AlertCard.tsx diff --git a/backend/src/controllers/program.ts b/backend/src/controllers/program.ts index f8f095c5..feca1913 100644 --- a/backend/src/controllers/program.ts +++ b/backend/src/controllers/program.ts @@ -16,7 +16,11 @@ export type Program = { color: string; //colorValueHex; hourlyPay: string; sessions: [string[]]; - archived?: boolean; + archived: boolean; +}; + +export type ExistingProgram = Program & { + dateUpdated: string; }; export const createProgram: RequestHandler = async (req, res, next) => { @@ -25,7 +29,10 @@ export const createProgram: RequestHandler = async (req, res, next) => { try { validationErrorParser(errors); - const programForm = await ProgramModel.create(req.body as Program); + const programForm = await ProgramModel.create({ + ...(req.body as Program), + dateUpdated: new Date().toISOString(), + }); res.status(201).json(programForm); } catch (error) { @@ -39,11 +46,11 @@ export const updateProgram: RequestHandler = async (req, res, next) => { validationErrorParser(errors); const programId = req.params.id; - const programData = req.body as Program; + const programData = req.body as ExistingProgram; const editedProgram = await ProgramModel.findOneAndUpdate( { _id: programId }, - { ...programData, archived: false }, //stand-in method of un-archiving programs + { ...programData, archived: false, dateUpdated: new Date().toISOString() }, //stand-in method of un-archiving programs { new: true, }, @@ -55,12 +62,12 @@ export const updateProgram: RequestHandler = async (req, res, next) => { // Waitlist all archived students. Making sure to only waitlist Archived students // will prevent enrollments from being updated every time the program is updated - const updateReport = await EnrollmentModel.updateMany( + await EnrollmentModel.updateMany( { programId: { $eq: programId }, status: { $eq: "Archived" } }, { $set: { status: "Waitlisted", dateUpdated: Date.now() } }, ); - res.status(200).json({ ...editedProgram, updateReport }); + res.status(200).json(editedProgram); } catch (error) { next(error); } @@ -72,17 +79,22 @@ export const archiveProgram: RequestHandler = async (req, res, next) => { validationErrorParser(errors); const programId = req.params.id; - const program = await ProgramModel.findByIdAndUpdate(programId, { $set: { archived: true } }); + const program = await ProgramModel.findByIdAndUpdate( + programId, + { $set: { archived: true, dateUpdated: new Date().toISOString() } }, + { new: true }, + ); if (!program) return res.status(404).json({ message: "Program with this id not found in database" }); //Archive all students - const updateReport = await EnrollmentModel.updateMany( + await EnrollmentModel.updateMany( { programId: { $eq: programId } }, { $set: { status: "Archived", dateUpdated: Date.now() } }, + { returnDocument: "after" }, ); - return res.status(200).json({ ...program, updateReport }); + return res.status(200).json(program); } catch (error) { next(error); } diff --git a/backend/src/models/program.ts b/backend/src/models/program.ts index ceb8b93a..ac4fa3fd 100644 --- a/backend/src/models/program.ts +++ b/backend/src/models/program.ts @@ -8,7 +8,9 @@ const programSchema = new Schema({ color: { type: String, required: true }, hourlyPay: { type: Number, required: true }, sessions: { type: [[String]], required: true }, - archived: { type: Boolean, required: false }, + archived: { type: Boolean, required: true }, + + dateUpdated: { type: String, required: true }, }); type Program = InferSchemaType; diff --git a/frontend/src/api/programs.ts b/frontend/src/api/programs.ts index b6484404..9c339b0b 100644 --- a/frontend/src/api/programs.ts +++ b/frontend/src/api/programs.ts @@ -3,7 +3,7 @@ import { CreateProgramRequest } from "../components/ProgramForm/types"; import type { APIResult } from "../api/requests"; -export type Program = CreateProgramRequest & { _id: string }; +export type Program = CreateProgramRequest & { _id: string; dateUpdated: string }; export async function createProgram(program: CreateProgramRequest): Promise> { try { diff --git a/frontend/src/components/AlertCard.tsx b/frontend/src/components/AlertCard.tsx new file mode 100644 index 00000000..6b81cf09 --- /dev/null +++ b/frontend/src/components/AlertCard.tsx @@ -0,0 +1,35 @@ +import { MouseEventHandler } from "react"; + +export default function AlertCard({ + message, + open, + onClose, +}: { + message: string; + open: boolean; + onClose: MouseEventHandler; +}) { + if (!open) return <>; + return ( +
+
+
+ + + +

{message}

+
+
+
+ ); +} diff --git a/frontend/src/components/ProgramCard.tsx b/frontend/src/components/ProgramCard.tsx index 911def7d..54db111d 100644 --- a/frontend/src/components/ProgramCard.tsx +++ b/frontend/src/components/ProgramCard.tsx @@ -16,6 +16,8 @@ export type CardProps = { isAdmin: boolean; className?: string; setPrograms: React.Dispatch>; + setAlertState: React.Dispatch>; + archiveView?: boolean; }; // function checkOffscreen(id: string) { @@ -53,7 +55,14 @@ function toggleEdit(id: string) { // } } -export function ProgramCard({ program, isAdmin, className, setPrograms }: CardProps) { +export function ProgramCard({ + program, + isAdmin, + className, + setPrograms, + setAlertState, + archiveView = false, +}: CardProps) { const { isTablet } = useWindowSize(); const editId = "edit" + program._id; @@ -95,8 +104,11 @@ export function ProgramCard({ program, isAdmin, className, setPrograms }: CardPr sessions: program.sessions, //students: program.students, archived: program.archived, + dateUpdated: program.dateUpdated, }; + const date = new Date(program.dateUpdated); + if (isTablet) { editClass += " top-7 w-12 h-5 text-[10px]"; outerDivClass += " rounded-lg h-36"; @@ -167,6 +179,7 @@ export function ProgramCard({ program, isAdmin, className, setPrograms }: CardPr component={editButton} data={programFields} setPrograms={setPrograms} + setAlertState={setAlertState} />
@@ -175,7 +188,7 @@ export function ProgramCard({ program, isAdmin, className, setPrograms }: CardPr

{program.type} Program

{program.name}

- {isAdmin && ( + {isAdmin && !archiveView && (
- students + {!archiveView && ( + students + )} {/*program.students.length === 0 &&

No Students

*/} {/*program.students.length === 1 &&

1 Student

*/} { //program.students.length > 1 && ( -

{/*program.students.length*/}0 Students

+

+ {/*program.students.length*/} + { + archiveView + ? "Archived on " + + (date.getMonth() + 1) + + "/" + + date.getDate() + + "/" + + date.getFullYear() + : "0 Students" //<---- Change in the future -------- + } +

//) }
diff --git a/frontend/src/components/ProgramForm/ProgramArchive.tsx b/frontend/src/components/ProgramForm/ProgramArchive.tsx index fd078a92..1218be6c 100644 --- a/frontend/src/components/ProgramForm/ProgramArchive.tsx +++ b/frontend/src/components/ProgramForm/ProgramArchive.tsx @@ -3,6 +3,7 @@ import { useForm } from "react-hook-form"; import { Program, archiveProgram } from "../../api/programs"; import { Button } from "../Button"; +import { ProgramMap } from "../StudentsTable/types"; import { Textfield } from "../Textfield"; import { Dialog, DialogClose, DialogContentSlide, DialogTrigger } from "../ui/dialog"; @@ -14,6 +15,8 @@ type archiveProps = { setOpenParent: React.Dispatch>; data: Program; isMobile?: boolean; + setPrograms: React.Dispatch>; + setAlertState: React.Dispatch>; }; function ProgramArchiveHeader({ label }: props) { @@ -48,7 +51,13 @@ function ProgramArchiveHeader({ label }: props) { } //Currently no functionality, just a button that closes the form -export default function ProgramArchive({ setOpenParent, data, isMobile = false }: archiveProps) { +export default function ProgramArchive({ + setOpenParent, + data, + isMobile = false, + setPrograms, + setAlertState, +}: archiveProps) { const [openArchive, setOpenArchive] = useState(false); const { register: archiveRegister, @@ -72,6 +81,13 @@ export default function ProgramArchive({ setOpenParent, data, isMobile = false } archiveReset(); setOpenArchive(false); setOpenParent(false); + setAlertState({ open: true, message: result.data.name + " has been archived" }); + setPrograms((prevPrograms: ProgramMap) => { + if (Object.keys(prevPrograms).includes(result.data._id)) + return { ...prevPrograms, [result.data._id]: { ...result.data } }; + else console.log("Program ID does not exist"); + return prevPrograms; + }); } else { console.log(result.error); alert("Unable to archive program: " + result.error); diff --git a/frontend/src/components/ProgramForm/types.ts b/frontend/src/components/ProgramForm/types.ts index 45fb49fa..114cff0b 100644 --- a/frontend/src/components/ProgramForm/types.ts +++ b/frontend/src/components/ProgramForm/types.ts @@ -7,6 +7,7 @@ export type ProgramData = { hourlyPay: string; sessions: [string[]]; archived: boolean; + dateUpdated: string; }; export type CreateProgramRequest = { diff --git a/frontend/src/components/ProgramFormButton.tsx b/frontend/src/components/ProgramFormButton.tsx index 6ec0cece..e685aa64 100644 --- a/frontend/src/components/ProgramFormButton.tsx +++ b/frontend/src/components/ProgramFormButton.tsx @@ -17,6 +17,7 @@ type BaseProperties = { classname?: string; component: React.JSX.Element; setPrograms: React.Dispatch>; + setAlertState: React.Dispatch>; }; type EditProperties = BaseProperties & { @@ -36,6 +37,7 @@ export default function ProgramFormButton({ component =

Please add a component

, data = null, setPrograms, + setAlertState, classname, }: ProgramFormProperties) { const { register, setValue: setCalendarValue, reset, handleSubmit } = useForm(); @@ -72,6 +74,7 @@ export default function ProgramFormButton({ if (result.success) { setOpenForm(false); console.log(`${type} program`, result.data); + setAlertState({ open: true, message: "Added program " + result.data.name }); setPrograms((prevPrograms: ProgramMap) => { return { ...prevPrograms, [result.data._id]: { ...result.data } }; }); @@ -86,13 +89,18 @@ export default function ProgramFormButton({ }); } if (type === "edit" && data) { - const updatedProgram: Program = { ...programRequest, _id: data._id }; + const updatedProgram: Program = { + ...programRequest, + _id: data._id, + dateUpdated: data.dateUpdated, + }; console.log(`${type} program`, updatedProgram); editProgram(updatedProgram) .then((result) => { if (result.success) { setOpenForm(false); console.log(`${type} program`, result.data); + setAlertState({ open: true, message: "Edited program " + result.data.name }); setPrograms((prevPrograms: ProgramMap) => { if (Object.keys(prevPrograms).includes(result.data._id)) return { ...prevPrograms, [result.data._id]: { ...result.data } }; @@ -122,7 +130,14 @@ export default function ProgramFormButton({ }} >
- {type === "edit" && data && } + {type === "edit" && data && ( + + )}

{type === "add" ? "Add new program" : data?.name} @@ -168,7 +183,13 @@ export default function ProgramFormButton({ /> {type === "edit" && data && ( - + )} {type === "add" ? ( diff --git a/frontend/src/pages/programs.tsx b/frontend/src/pages/programs.tsx index eda6f620..42359aa6 100644 --- a/frontend/src/pages/programs.tsx +++ b/frontend/src/pages/programs.tsx @@ -1,6 +1,7 @@ import Image from "next/image"; import React, { useContext, useMemo, useState } from "react"; +import AlertCard from "../components/AlertCard"; import { ProgramCard } from "../components/ProgramCard"; import ProgramFormButton from "../components/ProgramFormButton"; import { useWindowSize } from "../hooks/useWindowSize"; @@ -22,6 +23,11 @@ export default function Programs() { const [archiveView, setArchiveView] = useState(false); const [sliderOffset, setSliderOffset] = useState(0); + const [alertState, setAlertState] = useState<{ open: boolean; message: string }>({ + open: false, + message: "", + }); + const { allPrograms: programs, setAllPrograms: setPrograms, @@ -97,10 +103,16 @@ export default function Programs() {

Programs

{isAdmin && ( - + )} {/* Should be replaced with Add Button when created */}

+
program.archived === archiveView || program.archived === undefined ? (
- +
) : ( <> @@ -167,6 +185,12 @@ export default function Programs() { )} )} + { + setAlertState({ ...alertState, open: false }); + }} + /> ); } From 0e843df44c5003aca00552d480a3a0d0e7ac1dca Mon Sep 17 00:00:00 2001 From: mraysu Date: Thu, 30 May 2024 02:04:33 -0700 Subject: [PATCH 11/11] Mobile UI Adjustments --- backend/src/controllers/program.ts | 1 - frontend/src/components/AlertCard.tsx | 6 +++--- frontend/src/components/ProgramForm/ProgramArchive.tsx | 5 +++-- frontend/src/components/ProgramForm/ProgramCancel.tsx | 9 ++++++++- frontend/src/components/ProgramFormButton.tsx | 1 + 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/backend/src/controllers/program.ts b/backend/src/controllers/program.ts index feca1913..548ffed4 100644 --- a/backend/src/controllers/program.ts +++ b/backend/src/controllers/program.ts @@ -91,7 +91,6 @@ export const archiveProgram: RequestHandler = async (req, res, next) => { await EnrollmentModel.updateMany( { programId: { $eq: programId } }, { $set: { status: "Archived", dateUpdated: Date.now() } }, - { returnDocument: "after" }, ); return res.status(200).json(program); diff --git a/frontend/src/components/AlertCard.tsx b/frontend/src/components/AlertCard.tsx index 6b81cf09..e5224369 100644 --- a/frontend/src/components/AlertCard.tsx +++ b/frontend/src/components/AlertCard.tsx @@ -11,8 +11,8 @@ export default function AlertCard({ }) { if (!open) return <>; return ( -
-
+
+
-

{message}

+

{message}

diff --git a/frontend/src/components/ProgramForm/ProgramArchive.tsx b/frontend/src/components/ProgramForm/ProgramArchive.tsx index 1218be6c..9fb9c18f 100644 --- a/frontend/src/components/ProgramForm/ProgramArchive.tsx +++ b/frontend/src/components/ProgramForm/ProgramArchive.tsx @@ -101,19 +101,20 @@ export default function ProgramArchive({ return ( -
+
{!isMobile ? (