diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 35e32620..7b102c5e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -69,7 +69,7 @@ model User { Seniors Senior[] @relation(fields: [SeniorIDs], references: [id]) approved Approval @default(PENDING) ChapterID String? @db.ObjectId - Chapter Chapter? @relation(fields: [ChapterID], references: [id]) + Chapter Chapter? @relation(fields: [ChapterID], references: [id], onDelete: SetNull) userRequest UserRequest? } @@ -98,7 +98,7 @@ model Senior { folder String @default("") Files File[] ChapterID String @db.ObjectId - chapter Chapter @relation(fields: [ChapterID], references: [id]) + chapter Chapter @relation(fields: [ChapterID], references: [id], onDelete: Cascade) } model File { @@ -131,6 +131,8 @@ model ChapterRequest { motivation String availabilities String questions String + + chapter Chapter? } model Chapter { @@ -144,6 +146,11 @@ model Chapter { // Google Drive API related fields chapterFolder String @default("") permissions String[] + + chapterRequestId String @db.ObjectId @unique + chapterRequest ChapterRequest @relation(fields: [chapterRequestId], references: [id], onDelete: Cascade) + + userRequests UserRequest[] } model Resource { @@ -163,6 +170,7 @@ model UserRequest { // @deprecated - We ended up not using this anywhere approved Approval @default(PENDING) uid String @unique @db.ObjectId - chapterId String @db.ObjectId + chapterId String @db.ObjectId + chapter Chapter @relation(fields: [chapterId], references: [id], onDelete: Cascade) user User @relation(fields: [uid], references: [id]) } diff --git a/src/app/api/chapter/[chapterId]/route.client.ts b/src/app/api/chapter/[chapterId]/route.client.ts new file mode 100644 index 00000000..692d2ffc --- /dev/null +++ b/src/app/api/chapter/[chapterId]/route.client.ts @@ -0,0 +1,9 @@ +import { deleteChapterResponse } from "./route.schema"; + +export const deleteChapter = async (chapterId: string) => { + const response = await fetch(`/api/chapter/${chapterId}`, { + method: "DELETE", + }); + const json = await response.json(); + return deleteChapterResponse.parse(json); +}; diff --git a/src/app/api/chapter/[chapterId]/route.schema.ts b/src/app/api/chapter/[chapterId]/route.schema.ts new file mode 100644 index 00000000..ac3b529f --- /dev/null +++ b/src/app/api/chapter/[chapterId]/route.schema.ts @@ -0,0 +1,13 @@ +import { z } from "zod"; + +export const deleteChapterResponse = z.discriminatedUnion("code", [ + z.object({ + code: z.literal("SUCCESS"), + message: z.literal("The chapter was successfully deleted"), + }), + + z.object({ + code: z.literal("CHAPTER_NOT_FOUND"), + message: z.literal("The chapter id could not be found"), + }), +]); diff --git a/src/app/api/chapter/[chapterId]/route.ts b/src/app/api/chapter/[chapterId]/route.ts index 8053d588..7e6f5a09 100644 --- a/src/app/api/chapter/[chapterId]/route.ts +++ b/src/app/api/chapter/[chapterId]/route.ts @@ -1,25 +1,30 @@ -import { NextResponse } from "next/server"; import { withSessionAndRole } from "@server/decorator"; import { prisma } from "@server/db/client"; import { driveV3 } from "@server/service"; +import { NextResponse } from "next/server"; +import { deleteChapterResponse } from "./route.schema"; export const DELETE = withSessionAndRole(["ADMIN"], async ({ params }) => { - // TODO - // 1. Implement route.client.ts - // 2. Implement route.schema.ts - // 3. Finish deleting chapter - // 4. Add it to AdminHomePage - const chapterId = params.params.chapterId; const chapter = await prisma.chapter.findUnique({ where: { id: chapterId, }, + include: { + students: true, + seniors: true, + }, }); if (chapter == null) { // If no ID is found, chapter has been deleted by another admin. - return NextResponse.json("ok"); + return NextResponse.json( + deleteChapterResponse.parse({ + code: "CHAPTER_NOT_FOUND", + message: "Chapter not found", + }), + { status: 404 } + ); } await Promise.allSettled( @@ -31,5 +36,30 @@ export const DELETE = withSessionAndRole(["ADMIN"], async ({ params }) => { ) ); - return NextResponse.json("ok"); + await prisma.user.updateMany({ + where: { + ChapterID: chapterId, + }, + data: { + SeniorIDs: { + set: [], + }, + position: "", + role: "USER", + }, + }); + + await prisma.chapterRequest.delete({ + where: { + id: chapter.chapterRequestId, + }, + }); + + return NextResponse.json( + deleteChapterResponse.parse({ + code: "SUCCESS", + message: "The chapter was successfully deleted", + }), + { status: 200 } + ); }); diff --git a/src/app/api/handle-chapter-request/route.ts b/src/app/api/handle-chapter-request/route.ts index d6d66523..62efe493 100644 --- a/src/app/api/handle-chapter-request/route.ts +++ b/src/app/api/handle-chapter-request/route.ts @@ -59,6 +59,7 @@ export const POST = withSession(async ({ req }) => { data: { chapterName: chapterRequest.university, location: chapterRequest.universityAddress, + chapterRequestId: chapterRequest.id, }, }); diff --git a/src/components/AdminHomePage.tsx b/src/components/AdminHomePage.tsx index 2b93f95f..c505d44d 100644 --- a/src/components/AdminHomePage.tsx +++ b/src/components/AdminHomePage.tsx @@ -6,6 +6,8 @@ import { faTrashCan } from "@fortawesome/free-solid-svg-icons"; import { TileEdit } from "./TileGrid/TileEdit"; import { InfoTile } from "./TileGrid"; import { fullName } from "@utils"; +import { deleteChapter } from "@api/chapter/[chapterId]/route.client"; +import { useRouter } from "next/navigation"; import SearchableContainer from "./SearchableContainer"; type ChapterWithUser = Prisma.ChapterGetPayload<{ @@ -17,6 +19,8 @@ type AdminHomePageProps = { }; const AdminHomePage = ({ chapters }: AdminHomePageProps) => { + const router = useRouter(); + return ( { options.push({ name: "Remove Chapter", onClick: async () => { - return; + const response = await deleteChapter(chapter.id); + router.refresh(); }, color: "#ef6767", icon: , diff --git a/src/components/ChapterRequest.tsx b/src/components/ChapterRequest.tsx index 7634aeee..9b9f167c 100644 --- a/src/components/ChapterRequest.tsx +++ b/src/components/ChapterRequest.tsx @@ -114,7 +114,7 @@ const ChapterRequest = (props: ChapterRequestProps) => { ) : (
- +
)}