Skip to content

Commit

Permalink
Updated Archive Page View
Browse files Browse the repository at this point in the history
  • Loading branch information
mraysu committed May 30, 2024
1 parent 3f58cfb commit 15dc484
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 27 deletions.
30 changes: 21 additions & 9 deletions backend/src/controllers/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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) {
Expand All @@ -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,
},
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand Down
4 changes: 3 additions & 1 deletion backend/src/models/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof programSchema>;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/programs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<APIResult<Program>> {
try {
Expand Down
35 changes: 35 additions & 0 deletions frontend/src/components/AlertCard.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="absolute bottom-0 left-0 flex min-h-16 w-full justify-center">
<div className="z-20 flex max-h-12 min-w-[10%] max-w-[40%] items-center rounded-sm bg-black">
<div className="flex max-w-full flex-row items-center overflow-hidden " onClick={onClose}>
<svg
width="16"
height="16"
viewBox="0 0 10 10"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="m-4"
>
<path
d="M1.70711 0.292894C1.31658 -0.0976312 0.683417 -0.0976312 0.292893 0.292894C-0.0976311 0.683418 -0.0976311 1.31658 0.292893 1.70711L3.58579 5L0.292893 8.29289C-0.0976311 8.68342 -0.0976311 9.31658 0.292893 9.70711C0.683417 10.0976 1.31658 10.0976 1.70711 9.70711L5 6.41421L8.29289 9.70711C8.68342 10.0976 9.31658 10.0976 9.70711 9.70711C10.0976 9.31658 10.0976 8.68342 9.70711 8.29289L6.41421 5L9.70711 1.70711C10.0976 1.31658 10.0976 0.683418 9.70711 0.292894C9.31658 -0.0976301 8.68342 -0.0976301 8.29289 0.292894L5 3.58579L1.70711 0.292894Z"
fill="White"
/>
</svg>
<p className="truncate pr-4 text-white">{message}</p>
</div>
</div>
</div>
);
}
47 changes: 37 additions & 10 deletions frontend/src/components/ProgramCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export type CardProps = {
isAdmin: boolean;
className?: string;
setPrograms: React.Dispatch<React.SetStateAction<ProgramMap>>;
setAlertState: React.Dispatch<React.SetStateAction<{ open: boolean; message: string }>>;
archiveView?: boolean;
};

// function checkOffscreen(id: string) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -167,6 +179,7 @@ export function ProgramCard({ program, isAdmin, className, setPrograms }: CardPr
component={editButton}
data={programFields}
setPrograms={setPrograms}
setAlertState={setAlertState}
/>
</div>
<div className={outerDivClass}>
Expand All @@ -175,7 +188,7 @@ export function ProgramCard({ program, isAdmin, className, setPrograms }: CardPr
<p className={typeClass}>{program.type} Program</p>
<p className={titleClass}>{program.name}</p>
</div>
{isAdmin && (
{isAdmin && !archiveView && (
<div className={optionsDiv}>
<Image
id={optionsId}
Expand All @@ -190,18 +203,32 @@ export function ProgramCard({ program, isAdmin, className, setPrograms }: CardPr
</div>
<div className={botDivClass}>
<div className={numClass}>
<Image
alt="students"
src="/programs/Students.png"
height={12}
width={18}
className={iconClass}
/>
{!archiveView && (
<Image
alt="students"
src="/programs/Students.png"
height={12}
width={18}
className={iconClass}
/>
)}
{/*program.students.length === 0 && <p className={numTextClass}>No Students</p>*/}
{/*program.students.length === 1 && <p className={numTextClass}>1 Student</p>*/}
{
//program.students.length > 1 && (
<p className={numTextClass}>{/*program.students.length*/}0 Students</p>
<p className={numTextClass}>
{/*program.students.length*/}
{
archiveView
? "Archived on " +
(date.getMonth() + 1) +
"/" +
date.getDate() +
"/" +
date.getFullYear()
: "0 Students" //<---- Change in the future --------
}
</p>
//)
}
</div>
Expand Down
18 changes: 17 additions & 1 deletion frontend/src/components/ProgramForm/ProgramArchive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -14,6 +15,8 @@ type archiveProps = {
setOpenParent: React.Dispatch<React.SetStateAction<boolean>>;
data: Program;
isMobile?: boolean;
setPrograms: React.Dispatch<React.SetStateAction<ProgramMap>>;
setAlertState: React.Dispatch<React.SetStateAction<{ open: boolean; message: string }>>;
};

function ProgramArchiveHeader({ label }: props) {
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/ProgramForm/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type ProgramData = {
hourlyPay: string;
sessions: [string[]];
archived: boolean;
dateUpdated: string;
};

export type CreateProgramRequest = {
Expand Down
27 changes: 24 additions & 3 deletions frontend/src/components/ProgramFormButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type BaseProperties = {
classname?: string;
component: React.JSX.Element;
setPrograms: React.Dispatch<React.SetStateAction<ProgramMap>>;
setAlertState: React.Dispatch<React.SetStateAction<{ open: boolean; message: string }>>;
};

type EditProperties = BaseProperties & {
Expand All @@ -36,6 +37,7 @@ export default function ProgramFormButton({
component = <p>Please add a component</p>,
data = null,
setPrograms,
setAlertState,
classname,
}: ProgramFormProperties) {
const { register, setValue: setCalendarValue, reset, handleSubmit } = useForm<ProgramData>();
Expand Down Expand Up @@ -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 } };
});
Expand All @@ -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 } };
Expand Down Expand Up @@ -122,7 +130,14 @@ export default function ProgramFormButton({
}}
>
<form onSubmit={handleSubmit(onSubmit)} className={cn(classname)}>
{type === "edit" && data && <ProgramArchive setOpenParent={setOpenForm} data={data} />}
{type === "edit" && data && (
<ProgramArchive
setOpenParent={setOpenForm}
data={data}
setPrograms={setPrograms}
setAlertState={setAlertState}
/>
)}

<h2 className="mb-4 text-2xl font-bold text-neutral-800">
{type === "add" ? "Add new program" : data?.name}
Expand Down Expand Up @@ -168,7 +183,13 @@ export default function ProgramFormButton({
/>
<form onSubmit={handleSubmit(onSubmit)} className={cn(classname)}>
{type === "edit" && data && (
<ProgramArchive setOpenParent={setOpenForm} data={data} isMobile={isMobile} />
<ProgramArchive
setOpenParent={setOpenForm}
data={data}
isMobile={isMobile}
setPrograms={setPrograms}
setAlertState={setAlertState}
/>
)}

{type === "add" ? (
Expand Down
Loading

0 comments on commit 15dc484

Please sign in to comment.