Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cledi selena edit senior #111

Merged
merged 7 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ enum Role {
model Senior {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String @default("")
firstname String
lastname String
location String
description String
StudentIDs String[] @db.ObjectId
Expand Down
12 changes: 7 additions & 5 deletions src/app/api/senior/[id]/route.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ export const seniorDeleteResponse = z.discriminatedUnion("code", [
unauthorizedErrorSchema,
]);

export const patchSeniorSchema = z.object({
name: z.string(),
location: z.string(),
description: z.string(),
StudentIDs: z.array(z.string()),
export const patchSeniorSchema = seniorSchema.pick({
firstname: true,
lastname: true,
name: true, // TODO(nickbar01234) - Remove name
location: true,
StudentIDs: true,
description: true,
});

export type ISeniorSchema = z.infer<typeof seniorSchema>;
Expand Down
1 change: 0 additions & 1 deletion src/app/api/senior/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
patchSeniorSchema,
} from "./route.schema";
import { prisma } from "@server/db/client";
import { seniorSchema } from "@server/model";

/**
* @TODO - Delete folder belonging to the senior
Expand Down
12 changes: 7 additions & 5 deletions src/app/api/senior/route.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { z } from "zod";
import { unauthorizedErrorSchema, unknownErrorSchema } from "../route.schema";
import { seniorSchema } from "@server/model";

export const postSeniorSchema = z.object({
name: z.string(),
location: z.string(),
description: z.string(),
StudentIDs: z.array(z.string()),
export const postSeniorSchema = seniorSchema.pick({
firstname: true,
lastname: true,
name: true, // TODO(nickbar01234) - Remove name
location: true,
StudentIDs: true,
description: true,
});

export type IPostSeniorRequestSchema = z.infer<typeof postSeniorSchema>;
Expand Down
15 changes: 10 additions & 5 deletions src/app/api/senior/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const POST = withSessionAndRole(
{ status: 400 }
);
} else {
const seniorBody = newSenior.data;
const user = await prisma.user.findFirst({
where: {
id: session.user.id,
Expand All @@ -48,7 +49,9 @@ export const POST = withSessionAndRole(
}
const baseFolder = "1MVyWBeKCd1erNe9gkwBf7yz3wGa40g9a"; // TODO: make env variable
const fileMetadata = {
name: [`${body.name}-${randomUUID()}`],
name: [
`${seniorBody.firstname}_${seniorBody.lastname}-${randomUUID()}`,
],
mimeType: "application/vnd.google-apps.folder",
parents: [baseFolder],
};
Expand Down Expand Up @@ -82,11 +85,13 @@ export const POST = withSessionAndRole(

const senior = await prisma.senior.create({
data: {
name: body.name,
location: body.location,
description: body.description,
name: seniorBody.name,
firstname: seniorBody.firstname,
lastname: seniorBody.lastname,
location: seniorBody.location,
description: seniorBody.description,
ChapterID: session.user.ChapterID,
StudentIDs: body.StudentIDs,
StudentIDs: seniorBody.StudentIDs,
folder: googleFolderId,
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ const SeniorPage = async ({ params }: Params) => {
{ display: "Chapters", url: "chapters" },
{ display: user.Chapter?.chapterName ?? "", url: chapterId },
{ display: user.name ?? "", url: userId },
{ display: senior.name, url: seniorId },
{ display: `${senior.firstname} ${senior.lastname}`, url: seniorId },
]}
/>

<CardGrid
title={
<>
<h1 className="text-2xl font-bold text-[#000022]">{senior.name}</h1>
<h1 className="text-2xl font-bold text-[#000022]">{`${senior.firstname} ${senior.lastname}`}</h1>
{senior.description.length > 0 && (
<p className="text-[15px]">{senior.description}</p>
)}
Expand Down
6 changes: 6 additions & 0 deletions src/app/private/[uid]/chapter-leader/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ const UserLayout = ({ children }: IUserLayout) => {
link: `/private/${user.id}/chapter-leader/users`,
icon: faUserGroup,
},
// @TODO(nickbar01234) - Fix icon
{
name: "Seniors",
link: `/private/${user.id}/chapter-leader/seniors`,
icon: faUserGroup,
},
{
name: "Pending",
link: `/private/${user.id}/chapter-leader/pending`,
Expand Down
43 changes: 43 additions & 0 deletions src/app/private/[uid]/chapter-leader/seniors/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import { prisma } from "@server/db/client";
import { faUsers } from "@fortawesome/free-solid-svg-icons";
import { HeaderContainer } from "@components/container";
import { SeniorView } from "@components/SeniorView";

const UserSeniorsPage = async ({ params }: { params: { uid: string } }) => {
const userUid = params.uid;
const user = await prisma.user.findUnique({
where: {
id: userUid,
},
});
if (!user) {
return <div>User not found</div>;
}

// Fetch the seniors too
const chapter = await prisma.chapter.findFirst({
where: {
id: user.ChapterID ?? undefined,
},
include: {
seniors: {},
students: {},
},
});
const seniors = chapter?.seniors ? chapter.seniors : [];
const students = chapter?.students ? chapter.students : [];

return (
<HeaderContainer
header="Seniors"
showHorizontalLine={true}
headerIcon={faUsers}
>
<div className="mb-6 text-2xl">Seniors {`(${seniors.length})`}</div>
<SeniorView seniors={seniors} students={students} />
</HeaderContainer>
);
};

export default UserSeniorsPage;
2 changes: 1 addition & 1 deletion src/app/private/[uid]/user/seniors/SeniorsHomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type SeniorsHomePageProps = {
const SeniorsHomePage = ({ seniors, user }: SeniorsHomePageProps) => {
const displaySeniors = (elem: Senior, index: number) => (
<UserTile
key={index}
key={elem.id}
senior={elem}
link={`/private/${user.id}/user/seniors/${elem.id}`}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/app/private/[uid]/user/seniors/[seniorId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const Page = async ({ params }: PageProps) => {
pathInfo={[
{ display: "Seniors", url: `/private/${params.uid}/user/seniors` },
{
display: senior.name,
display: `${senior.firstname} ${senior.lastname}`,
url: `/private/${params.uid}/seniors/${senior.id}`,
},
]}
Expand Down
64 changes: 30 additions & 34 deletions src/components/AddSenior.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import FilterDropdown from "@components/FilterDropdown";
import { Senior, User } from "@prisma/client";
import ImageIcon from "../../public/icons/icon_add_photo.png";
import { patchSenior } from "src/app/api/senior/[id]/route.client";
import { postSenior } from "src/app/api/senior/route.client";
import z from "zod/lib";
import { seniorSchema } from "@server/model";

type AddSeniorProps = {
seniors: Senior[];
Expand Down Expand Up @@ -83,11 +86,15 @@ const StudentSelector = ({
);
};

type SeniorData = {
name: string;
location: string;
description: string;
};
// type SeniorData = Omit<
// Extract<z.infer<typeof seniorPostResponse>, { code: "SUCCESS" }>["data"],
// "StudentIDs"
// >;

type SeniorData = Pick<
z.infer<typeof seniorSchema>,
"firstname" | "lastname" | "name" | "location" | "description"
>;

const AddSenior = ({
seniors,
Expand All @@ -99,6 +106,8 @@ const AddSenior = ({
setSeniorPatch,
}: AddSeniorProps) => {
const emptySenior: SeniorData = {
firstname: "",
lastname: "",
name: "",
location: "",
description: "",
Expand Down Expand Up @@ -157,36 +166,23 @@ const AddSenior = ({
// put accumulated students into senior model data
const seniorModel = {
...seniorData,
StudentIDs: selectedStudents.map((usr) => {
console.log(usr.id);
return usr.id;
}),
name: `${seniorData.firstname} ${seniorData.lastname}`,
StudentIDs: selectedStudents.map((usr) => usr.id),
};

// POST new senior model to database
const currRes = await fetch("/api/seniors/add", {
method: "POST",
body: JSON.stringify(seniorModel),
postSenior({ body: seniorModel }).then((res) => {
if (res.code === "SUCCESS") {
// PATCH students models previously and newly associated with senior model
setConfirm(true);
setSeniors([...seniors, res.data]);
} else {
setError(true);
}
setSeniorData(emptySenior);
setSelectedStudents([]);
return null;
});
const newSeniorObj = await currRes.json();

if (currRes.status === 200) {
// PATCH students models previously and newly associated with senior model
setConfirm(true);
setSeniors([...seniors, newSeniorObj]);
}
// check after both API calls
if (currRes.status != 200) {
console.log(
currRes.text().then((text) => {
console.log(text);
})
);
setError(true);
}

setSeniorData(emptySenior);
setSelectedStudents([]);
};

const handleImageReplace = (event: React.ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -257,7 +253,7 @@ const AddSenior = ({
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setSeniorData({
...seniorData,
name: e.target.value,
firstname: e.target.value,
})
}
/>
Expand All @@ -271,10 +267,10 @@ const AddSenior = ({
<input
className="mb-3 h-[36px] w-full rounded-md border-2 border-solid border-tan px-3 text-sm text-black"
type="text"
onBlur={(e: React.ChangeEvent<HTMLInputElement>) =>
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setSeniorData((seniorData) => ({
...seniorData,
name: seniorData.name + " " + e.target.value,
lastname: e.target.value,
}))
}
/>
Expand Down
45 changes: 45 additions & 0 deletions src/components/SeniorView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"use client";

import { Senior, User } from "@prisma/client";
import SearchableContainer from "./SearchableContainer";
import { UserTile } from "./TileGrid";
import AddSenior from "./AddSenior";
import { useState } from "react";

type SeniorViewProps = {
seniors: Senior[];
students: User[];
};

export const SeniorView = ({ seniors, students }: SeniorViewProps) => {
const [seniorsState, setSeniorsState] = useState(seniors);
const [showAddSeniorPopUp, setShowAddSeniorPopUp] = useState(false);
const [seniorPatch, setSeniorPatch] = useState("");

return (
<SearchableContainer<Senior>
addElementComponent={
<AddSenior
selenaz03 marked this conversation as resolved.
Show resolved Hide resolved
key="add-senior"
seniors={seniorsState}
students={students}
setSeniors={setSeniorsState}
showAddSeniorPopUp={showAddSeniorPopUp}
setShowAddSeniorPopUp={setShowAddSeniorPopUp}
seniorPatch={seniorPatch}
setSeniorPatch={setSeniorPatch}
/>
}
elements={seniorsState ? seniorsState : []}
display={(senior, index) => (
// TODO(nickbar01234) - Fix link
<UserTile senior={senior} link="bleh" key={senior.id} />
)}
search={(senior, key) =>
(senior.firstname + " " + senior.lastname)
.toLowerCase()
.includes(key.toLowerCase())
}
/>
);
};
8 changes: 6 additions & 2 deletions src/components/TileGrid/SeniorTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ export function SeniorTile({
},
];

console.log(senior.name + "'s Students: " + senior.StudentIDs.toString());
console.log(
`${senior.firstname} ${senior.lastname}` +
"'s Students: " +
senior.StudentIDs.toString()
);

return (
<div className="relative flex aspect-square w-auto flex-col items-center rounded bg-white font-medium drop-shadow-md hover:bg-off-white">
Expand All @@ -77,7 +81,7 @@ export function SeniorTile({
<div className="text-md text-neutral-600 relative flex h-1/2 w-full flex-col p-2 text-center font-medium">
<span className="break-words px-2 font-semibold">
{" "}
{senior.name}{" "}
{`${senior.firstname} ${senior.lastname}`}{" "}
</span>
<p className="text-md font-base text-neutral-600 truncate px-2">
{senior.location}
Expand Down
4 changes: 2 additions & 2 deletions src/components/TileGrid/UserTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ export function UserTile({
<p className="overflow-hidden text-ellipsis whitespace-nowrap text-sm text-dark-teal">
{student && student.name
? student.name + (student.admin ? " (Admin)" : "")
: senior
? senior.name
: senior && `${senior.firstname} ${senior.lastname}`
? `${senior.firstname} ${senior.lastname}`
: null}
</p>
{/* @TODO: Add pronouns once we add to student field */}
Expand Down
2 changes: 1 addition & 1 deletion src/components/senior/DisplaySenior.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const DisplaySenior = (props: DisplayProps) => {
return (
<div className="flex flex-col gap-y-6">
{/* @TODO - Firstname + lastname */}
<h1 className="text-4xl font-bold text-[#000022]">{senior.name}</h1>
<h1 className="text-4xl font-bold text-[#000022]">{`${senior.firstname} ${senior.lastname}`}</h1>
<p>{senior.description}</p>
<Assigment editable={editable} senior={senior} />
<SearchableContainer
Expand Down
2 changes: 2 additions & 0 deletions src/components/senior/assignment/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const Assignment = (props: AssignmentProps) => {
onSave={async () => {
await patchSenior({
body: {
firstname: senior.firstname,
lastname: senior.lastname,
name: senior.name,
location: senior.location,
description: senior.description,
Expand Down
Loading
Loading