Skip to content

Commit

Permalink
Feature/andrewzpu/program page (#62)
Browse files Browse the repository at this point in the history
* Created Program Card Component

* Edited Programs Page Layout

* Added Create Program Button and Minor Edits

* Finished editing Programs Page

* made lint fixes

* added backend route to get all programs

* fix deploy issue

* connected programs page to backend route

* fixed windowSize width error

* minor text changes

* fixed program card color options

* Added Options button and fixed lint errors

* fixed lint issues

* implemented edit program in program page

* uncommented 404 error lines

* reset default api path to /api

---------

Co-authored-by: adhi0331 <[email protected]>
Co-authored-by: Adhithya Ananthan <[email protected]>
  • Loading branch information
3 people authored Apr 15, 2024
1 parent 3f535ba commit f204c4f
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 20 deletions.
1 change: 0 additions & 1 deletion backend/src/routes/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import * as ProgramValidator from "../validators/program";

const router = express.Router();

router.post("/", ProgramValidator.createProgram, ProgramController.createProgram);
router.patch("/:id", ProgramValidator.updateProgram, ProgramController.updateProgram);
router.post("/create", ProgramValidator.createProgram, ProgramController.createProgram);
router.get("/all", ProgramController.getAllPrograms);
Expand Down
Binary file added frontend/public/programs/Options.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/programs/Students.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/programs/Vector.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
127 changes: 127 additions & 0 deletions frontend/src/components/ProgramCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { Poppins } from "next/font/google";
import React from "react";

import { Program } from "../api/programs";
import ProgramFormButton from "../components/ProgramFormButton";
import { useWindowSize } from "../hooks/useWindowSize";
import { cn } from "../lib/utils";

import { ProgramData } from "./ProgramForm/types";

const poppins = Poppins({ weight: ["400", "700"], style: "normal", subsets: [] });

export type CardProps = {
program: Program;
type: string;
title: string;
dates: string;
color: string;
className?: string;
};

export function ProgramCard({ program, type, title, dates, color, className }: CardProps) {
const { isTablet } = useWindowSize();

let outerDivClass = "text-white grow overflow-hidden tracking-wide leading-6";
let topDivClass = "flex flex-row";
console.log(topDivClass);
let botDivClass = "text-black bg-white";
let typeClass;
let titleClass;
let optionsDiv = "grow";
const optionsClass = "relative float-right hover:cursor-pointer";
let dateClass;
// let numClass;
// let numTextClass;
// let iconClass = "relative";

let tempDate = new Date(program.startDate);
const startDate =
("0" + (tempDate.getMonth() + 1)).slice(-2) +
"/" +
("0" + tempDate.getDate()).slice(-2) +
"/" +
tempDate.getFullYear();

tempDate = new Date(program.endDate);
const endDate =
("0" + (tempDate.getMonth() + 1)).slice(-2) +
"/" +
("0" + tempDate.getDate()).slice(-2) +
"/" +
tempDate.getFullYear();

const programData: ProgramData = {
name: program.name,
abbreviation: program.abbreviation,
type: program.type,
days: program.daysOfWeek,
start: startDate,
end: endDate,
color: program.color,
renewal: "",
hourly: "",
sessions: [[]],
};

if (isTablet) {
outerDivClass += " rounded-lg h-36";
topDivClass += " h-20";
botDivClass += " h-16";
typeClass = cn("uppercase relative text-[10px] top-2 left-3", poppins.className);
titleClass = cn("capitalize relative text-sm top-2 left-3 font-bold", poppins.className);
optionsDiv += " pr-[8px] pt-[12px]";
dateClass = cn("relative text-[10px] top-2 left-3", poppins.className);
// numClass = "h-5 gap-x-1.5 flex flex-row relative top-2 left-3";
// numTextClass = cn("text-[10px]", poppins.className);
// iconClass = "h-2 w-3 mt-[7px]";
} else {
outerDivClass += " rounded-2xl h-68";
topDivClass += " h-36";
botDivClass += " h-32";
typeClass = cn("uppercase relative text-sm top-5 left-7", poppins.className);
titleClass = cn("capitalize relative text-3xl top-8 left-7 font-bold", poppins.className);
optionsDiv += " pr-[16px] pt-[24px]";
dateClass = cn("relative text-base top-5 left-7", poppins.className);
// numClass = "h-8 gap-x-1.5 flex flex-row relative top-14 left-7";
// numTextClass = cn("text-base", poppins.className);
// iconClass = "h-3 w-[18px] mt-[5px]";
}

if (className) {
outerDivClass = cn(outerDivClass, className);
}

console.log(topDivClass);

return (
<div className={outerDivClass}>
<div className={topDivClass} style={{ backgroundColor: color }}>
<div>
<p className={typeClass}>{type} Program</p>
<p className={titleClass}>{title}</p>
</div>
<div className={optionsDiv}>
<div className={optionsClass}>
<ProgramFormButton type="edit" data={programData} />{" "}
</div>
</div>
</div>
<div className={botDivClass}>
<p className={dateClass}>{dates}</p>
{/*
<div className={numClass}>
<Image
alt="students"
src="/programs/Vector.png"
height={12}
width={18}
className={iconClass}
/>
<p className={numTextClass}>{numStudents} Students</p>
</div>
*/}
</div>
</div>
);
}
59 changes: 43 additions & 16 deletions frontend/src/components/ProgramFormButton.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Image from "next/image";
import { useMemo, useState } from "react";
import { SubmitHandler, useForm } from "react-hook-form";

Expand Down Expand Up @@ -55,14 +56,27 @@ export default function ProgramFormButton({
return !isMobile ? (
<>
<Dialog open={openForm} onOpenChange={setOpenForm}>
<DialogTrigger asChild>
<Button
label={type === "add" ? "Add Program" : "Edit Program"}
onClick={() => {
setOpenForm(true);
}}
/>
</DialogTrigger>
{type === "add" && (
<DialogTrigger asChild>
<Button
label="Add Program"
onClick={() => {
setOpenForm(true);
}}
/>
</DialogTrigger>
)}
{type === "edit" && (
<DialogTrigger asChild>
<Image
alt="options"
src="/programs/Options.png"
height={18}
width={16}
className={"relative float-right hover:cursor-pointer"}
/>
</DialogTrigger>
)}
<DialogContentSlide className="w-full bg-white object-right p-6 sm:w-[50%]">
<form onSubmit={handleSubmit(onSubmit)} className={cn(classname)}>
{type === "edit" && (
Expand Down Expand Up @@ -155,14 +169,27 @@ export default function ProgramFormButton({
) : (
<>
<Dialog open={openForm} onOpenChange={setOpenForm}>
<DialogTrigger asChild>
<Button
label={type === "add" ? "Add Program" : "Edit Program"}
onClick={() => {
setOpenForm(true);
}}
/>
</DialogTrigger>
{type === "add" && (
<DialogTrigger asChild>
<Button
label="Add Program"
onClick={() => {
setOpenForm(true);
}}
/>
</DialogTrigger>
)}
{type === "edit" && (
<DialogTrigger asChild>
<Image
alt="options"
src="/programs/Options.png"
height={9}
width={8}
className={"relative float-right hover:cursor-pointer"}
/>
</DialogTrigger>
)}
<DialogContent className="bg-white p-3">
<ProgramCancel
onSubmit={() => {
Expand Down
95 changes: 92 additions & 3 deletions frontend/src/pages/programs.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,104 @@
import React, { useEffect, useMemo, useState } from "react";

import { Program, getAllPrograms } from "../api/programs";
import { ProgramCard } from "../components/ProgramCard";
import ProgramFormButton from "../components/ProgramFormButton";
import { useWindowSize } from "../hooks/useWindowSize";

import { useRedirectTo404IfNotAdmin, useRedirectToLoginIfNotSignedIn } from "@/hooks/redirect";

function processDate(startString: Date): string {
const startDate = new Date(startString);

const options = {
year: "numeric",
month: "short",
day: "numeric",
} as const;

return "Started " + startDate.toLocaleDateString("en-US", options);
}

export default function Programs() {
useRedirectToLoginIfNotSignedIn();
useRedirectTo404IfNotAdmin();

const { windowSize } = useWindowSize();
const isMobile = useMemo(() => windowSize.width < 640, [windowSize.width]);
const isTablet = useMemo(() => windowSize.width < 1024, [windowSize.width]);
const extraLarge = useMemo(() => windowSize.width >= 2000, [windowSize.width]);

const [programs, setPrograms] = useState<Program[]>([]);

useEffect(() => {
getAllPrograms().then(
(result) => {
if (result.success) {
setPrograms(result.data);
} else {
alert(result.error);
}
},
(error) => {
console.log(error);
},
);
}, []);

let mainClass = "h-full overflow-y-scroll no-scrollbar";
let titleClass = "font-[alternate-gothic]";
let headerClass = "flex flex-row";
let cardsGridClass = "grid";
let cardClass = "";

if (isTablet) {
titleClass += " text-2xl leading-none h-6";
mainClass += " p-0";

if (isMobile) {
headerClass += " pt-2 pb-3";
cardsGridClass += " grid-cols-1";
cardClass += " p-0 py-3";
} else {
cardsGridClass += " grid-cols-2";
headerClass += " p-2 py-4";
cardClass += " p-2";
}
} else {
titleClass += " text-[40px] leading-none h-10";
headerClass += " p-5 pt-10 pb-5";
cardClass += " p-5";

if (extraLarge) {
cardsGridClass += " grid-cols-3 max-w-[1740px]";
headerClass += " max-w-[1740px]";
} else {
cardsGridClass += " grid-cols-2 max-w-[1160px]";
headerClass += " max-w-[1160px]";
}
}

return (
<div>
<div className="w-40">
<main className={mainClass}>
<div className={headerClass}>
<h1 className={titleClass}>Programs</h1>
<div className="grow"></div>
{/* Should be replaced with Add Button when created */}
<ProgramFormButton type="add" />{" "}
</div>
</div>
<div className={cardsGridClass}>
{programs.map((program) => (
<div className={cardClass} key={program._id}>
<ProgramCard
program={program}
type={program.type}
title={program.name}
dates={processDate(program.startDate)}
color={program.color}
/>
</div>
))}
</div>
</main>
);
}
4 changes: 4 additions & 0 deletions frontend/src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@
}

@layer utilities {
.no-scrollbar::-webkit-scrollbar {
display: none;
}

.scrollbar::-webkit-scrollbar {
width: 12px;
}
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
--primary-dark-green: 0, 104, 103;
--primary-text: 32, 33, 36;
--white: 255, 255, 255;

--secondary-yellow: 255, 184, 0;
--secondary-red: 255, 122, 94;
--secondary-teal: 79, 161, 151;
--secondary-green: 182, 191, 14;

--error-red: 185, 59, 69;
--gray-2: 216, 216, 216;
--black: 0, 0, 0;
Expand Down

0 comments on commit f204c4f

Please sign in to comment.