diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c9af638e..3c1b2b75 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -46,7 +46,7 @@ model Session { } model User { - id String @id @default(auto()) @map("_id") @db.ObjectId + id String @id @default(auto()) @map("_id") @db.ObjectId // https://github.com/nextauthjs/next-auth/blob/v4/packages/next-auth/src/providers/google.ts // Fields mappable from PrismaAdapter. We can map the value return from profle() in [...nextauth]. @@ -86,7 +86,7 @@ enum Role { model Senior { id String @id @default(auto()) @map("_id") @db.ObjectId - name String + name String @default("") location String description String StudentIDs String[] @db.ObjectId @@ -98,13 +98,13 @@ model Senior { } model File { - id String @id @default(auto()) @map("_id") @db.ObjectId - date DateTime // will zero out the hours - filetype String - url String - seniorId String @db.ObjectId - senior Senior @relation(fields: [seniorId], references: [id], onDelete: Cascade) - Tags String[] + id String @id @default(auto()) @map("_id") @db.ObjectId + date DateTime // will zero out the hours + filetype String + url String + seniorId String @db.ObjectId + senior Senior @relation(fields: [seniorId], references: [id], onDelete: Cascade) + Tags String[] @@unique([seniorId, date]) } @@ -134,20 +134,20 @@ model Chapter { } model Resource { - id String @id @default(auto()) @map("_id") @db.ObjectId - access Role[] - link String - title String + id String @id @default(auto()) @map("_id") @db.ObjectId + access Role[] + link String + title String } model Email { - id String @id @default(auto()) @map("_id") @db.ObjectId - email String @unique + id String @id @default(auto()) @map("_id") @db.ObjectId + email String @unique } model UserRequest { - id String @id @default(auto()) @map("_id") @db.ObjectId - approved Approval @default(PENDING) - uid String @db.ObjectId @unique - chapterId String @db.ObjectId -} \ No newline at end of file + id String @id @default(auto()) @map("_id") @db.ObjectId + approved Approval @default(PENDING) + uid String @unique @db.ObjectId + chapterId String @db.ObjectId +} diff --git a/src/app/private/[uid]/chapter-leader/edit-profile/layout.tsx b/src/app/private/[uid]/chapter-leader/edit-profile/layout.tsx new file mode 100644 index 00000000..9946e8ba --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/edit-profile/layout.tsx @@ -0,0 +1,20 @@ +import { HeaderContainer } from "@components/container/index"; +import { faUser } from "@fortawesome/free-regular-svg-icons"; + +interface IEditProfileLayout { + children: React.ReactNode; +} + +const EditProfileLayout = ({ children }: IEditProfileLayout) => { + return ( + + {children} + + ); +}; + +export default EditProfileLayout; diff --git a/src/app/private/[uid]/chapter-leader/edit-profile/page.tsx b/src/app/private/[uid]/chapter-leader/edit-profile/page.tsx new file mode 100644 index 00000000..6dace489 --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/edit-profile/page.tsx @@ -0,0 +1,3 @@ +import { EditProfileForm } from "@components/user"; + +export default EditProfileForm; diff --git a/src/app/private/[uid]/chapter-leader/home/@joinChapter/page.tsx b/src/app/private/[uid]/chapter-leader/home/@joinChapter/page.tsx new file mode 100644 index 00000000..6440defe --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/home/@joinChapter/page.tsx @@ -0,0 +1,31 @@ +import { UserJoinRequest } from "@components/user"; +import { prisma } from "@server/db/client"; + +interface UserHomePageParams { + params: { + uid: string; + }; +} + +const UserJoinChapterPage = async ({ params }: UserHomePageParams) => { + const chapters = await prisma.chapter.findMany({ + include: { + students: true, + }, + }); + const joinRequest = await prisma.userRequest.findFirst({ + where: { + uid: params.uid, + }, + }); + + return ( + + ); +}; + +export default UserJoinChapterPage; diff --git a/src/app/private/[uid]/chapter-leader/home/layout.tsx b/src/app/private/[uid]/chapter-leader/home/layout.tsx new file mode 100644 index 00000000..244e61a5 --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/home/layout.tsx @@ -0,0 +1,42 @@ +import { prisma } from "@server/db/client"; +import TabButtons from "@components/TabButtons"; +import { HeaderContainer } from "@components/container/index"; +import { faHouse } from "@fortawesome/free-solid-svg-icons"; + +interface LayoutProps { + children: React.ReactNode; + joinChapter: React.ReactNode; + params: { + uid: string; + }; +} + +const Layout = async ({ children, params, joinChapter }: LayoutProps) => { + const user = await prisma.user.findFirstOrThrow({ + where: { + id: params.uid, + }, + }); + + if (user.ChapterID != null) { + return ( + + + {children} + + ); + } else { + return joinChapter; + } +}; + +export default Layout; diff --git a/src/app/private/[uid]/chapter-leader/home/page.tsx b/src/app/private/[uid]/chapter-leader/home/page.tsx new file mode 100644 index 00000000..e3f666f9 --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/home/page.tsx @@ -0,0 +1,55 @@ +import { UserTile } from "@components/TileGrid"; +import DisplayChapterInfo from "@components/DisplayChapterInfo"; +import { prisma } from "@server/db/client"; +import { CardGrid } from "@components/container"; + +interface UserHomePageParams { + params: { + uid: string; + }; +} + +const UserHomePage = async ({ params }: UserHomePageParams) => { + const user = await prisma.user.findFirstOrThrow({ + where: { + id: params.uid, + }, + }); + const chapter = await prisma.chapter.findFirstOrThrow({ + where: { + id: user.ChapterID ?? "", + }, + include: { + students: true, + }, + }); + + return ( +
+
+ {chapter.chapterName} +
+ user.role == "USER").length + } + dateCreated={chapter.dateCreated} + /> + + Executive Board +
+ } + tiles={chapter.students + .filter((user) => user.role == "CHAPTER_LEADER") + .map((user) => ( + + ))} + /> + + ); +}; + +export default UserHomePage; diff --git a/src/app/private/[uid]/chapter-leader/layout.tsx b/src/app/private/[uid]/chapter-leader/layout.tsx new file mode 100644 index 00000000..56845964 --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/layout.tsx @@ -0,0 +1,55 @@ +"use client"; + +import Sidebar, { ISideBar } from "@components/Sidebar"; +import { + faHome, + faUser, + faUserGroup, + faUserPlus, +} from "@fortawesome/free-solid-svg-icons"; +import React, { useContext } from "react"; +import { UserContext } from "src/context/UserProvider"; + +interface IUserLayout { + children: React.ReactNode; +} + +const UserLayout = ({ children }: IUserLayout) => { + const { user } = useContext(UserContext); + const buttons: ISideBar["buttons"] = React.useMemo( + () => [ + { + name: "Home", + link: `/private/${user.id}/chapter-leader/home`, + icon: faHome, + }, + { + name: "Members", + link: `/private/${user.id}/chapter-leader/members`, + icon: faUserGroup, + }, + { + name: "Pending", + link: `/private/${user.id}/chapter-leader/pending`, + icon: faUserPlus, + }, + { + name: "Profile", + link: `/private/${user.id}/chapter-leader/edit-profile`, + icon: faUser, + }, + ], + [user.id] + ); + + return ( +
+
+ +
+
{children}
+
+ ); +}; + +export default UserLayout; diff --git a/src/app/private/[uid]/chapter-leader/members/MembersHomePage.tsx b/src/app/private/[uid]/chapter-leader/members/MembersHomePage.tsx new file mode 100644 index 00000000..07653e89 --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/members/MembersHomePage.tsx @@ -0,0 +1,52 @@ +"use client"; + +import { useState } from "react"; +import { UserTile } from "@components/TileGrid"; +import { CardGrid } from "@components/container"; +import SearchBar from "@components/SearchBar"; +import { User } from "@prisma/client"; + +type MembersHomePageProps = { + members: User[]; + user: User; +}; + +const MembersHomePage = ({ members, user }: MembersHomePageProps) => { + const [filter, setFilter] = useState(""); + + return ( + <> +

+ {`Members (${members.length})`} +

+
+ +
+ {members.length > 0 ? ( + + (member.firstName + " " + member.lastName) + .toLowerCase() + .includes(filter.toLowerCase()) + ) + .map((member, index) => { + return ( + + ); + })} + /> + ) : ( +

+ {"This chapter has no members."} +

+ )} + + ); +}; + +export default MembersHomePage; diff --git a/src/app/private/[uid]/chapter-leader/members/layout.tsx b/src/app/private/[uid]/chapter-leader/members/layout.tsx new file mode 100644 index 00000000..b52667ac --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/members/layout.tsx @@ -0,0 +1,20 @@ +import { HeaderContainer } from "@components/container"; +import { faUserGroup } from "@fortawesome/free-solid-svg-icons"; + +interface LayoutProps { + children?: React.ReactNode; +} + +const Layout = (props: LayoutProps) => { + return ( + + {props.children} + + ); +}; + +export default Layout; diff --git a/src/app/private/[uid]/chapter-leader/members/page.tsx b/src/app/private/[uid]/chapter-leader/members/page.tsx new file mode 100644 index 00000000..1165f864 --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/members/page.tsx @@ -0,0 +1,24 @@ +import React from "react"; +import { prisma } from "@server/db/client"; +import MembersHomePage from "./MembersHomePage"; + +const MembersPage = async ({ params }: { params: { uid: string } }) => { + const user = await prisma.user.findFirstOrThrow({ + where: { + id: params.uid, + }, + }); + + const chapter = await prisma.chapter.findFirstOrThrow({ + where: { + id: user.ChapterID ?? "", + }, + include: { + students: true, + }, + }); + + return ; +}; + +export default MembersPage; diff --git a/src/app/private/[uid]/chapter-leader/pending/PendingHomePage.tsx b/src/app/private/[uid]/chapter-leader/pending/PendingHomePage.tsx new file mode 100644 index 00000000..29644307 --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/pending/PendingHomePage.tsx @@ -0,0 +1,34 @@ +"use client"; + +import PendingCard from "@components/PendingCard"; +import { CardGrid } from "@components/container"; +import { User } from "@prisma/client"; + +type MembersHomePageProps = { + users: User[]; +}; + +const PendingHomePage = ({ users }: MembersHomePageProps) => { + return ( + <> +

+ {`Pending (${users.length})`} +

+ {users.length > 0 ? ( + { + return ( + + ); + })} + /> + ) : ( +

+ {"This chapter has no members."} +

+ )} + + ); +}; + +export default PendingHomePage; diff --git a/src/app/private/[uid]/chapter-leader/pending/layout.tsx b/src/app/private/[uid]/chapter-leader/pending/layout.tsx new file mode 100644 index 00000000..b52667ac --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/pending/layout.tsx @@ -0,0 +1,20 @@ +import { HeaderContainer } from "@components/container"; +import { faUserGroup } from "@fortawesome/free-solid-svg-icons"; + +interface LayoutProps { + children?: React.ReactNode; +} + +const Layout = (props: LayoutProps) => { + return ( + + {props.children} + + ); +}; + +export default Layout; diff --git a/src/app/private/[uid]/chapter-leader/pending/page.tsx b/src/app/private/[uid]/chapter-leader/pending/page.tsx new file mode 100644 index 00000000..92db5f09 --- /dev/null +++ b/src/app/private/[uid]/chapter-leader/pending/page.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import { prisma } from "@server/db/client"; +import PendingHomePage from "./PendingHomePage"; +import { User } from "@prisma/client"; + +const PendingPage = async ({ params }: { params: { uid: string } }) => { + const user = await prisma.user.findFirstOrThrow({ + where: { + id: params.uid, + }, + }); + + const userRequests = await prisma.userRequest.findMany({ + where: { + chapterId: user.ChapterID ?? "", + }, + }); + + const users: User[] = []; + + for (let i = 0; i < userRequests.length; i++) { + const user = await prisma.user.findFirstOrThrow({ + where: { + id: userRequests[i]?.uid ?? "", + }, + }); + + users.push(user); + } + + return ; +}; + +export default PendingPage; diff --git a/src/app/private/[uid]/user/layout.tsx b/src/app/private/[uid]/user/layout.tsx index 7277efa2..4cf917fa 100644 --- a/src/app/private/[uid]/user/layout.tsx +++ b/src/app/private/[uid]/user/layout.tsx @@ -1,6 +1,10 @@ "use client"; +<<<<<<< HEAD import { CollapsableSidebarContainer } from "@components/container"; +======= +import Sidebar, { ISideBar } from "@components/Sidebar"; +>>>>>>> 9bd5bd7 (finish first draft) import { faHome, faUsers, faUser } from "@fortawesome/free-solid-svg-icons"; import React, { useContext } from "react"; import { UserContext } from "src/context/UserProvider"; diff --git a/src/app/private/[uid]/user/seniors/SeniorsHomePage.tsx b/src/app/private/[uid]/user/seniors/SeniorsHomePage.tsx index 304a89b7..2448f666 100644 --- a/src/app/private/[uid]/user/seniors/SeniorsHomePage.tsx +++ b/src/app/private/[uid]/user/seniors/SeniorsHomePage.tsx @@ -19,25 +19,33 @@ const SeniorsHomePage = ({ seniors, user }: SeniorsHomePageProps) => { return ( <> +

+ {`My Assigned Seniors (${seniors.length})`} +

- - senior.name.toLowerCase().includes(filter.toLowerCase()) - ) - .map((senior, index) => { - return ( - - ); - })} - /> + {seniors.length > 0 ? ( + + senior.name.toLowerCase().includes(filter.toLowerCase()) + ) + .map((senior, index) => { + return ( + + ); + })} + /> + ) : ( +

+ {"You haven't been assigned a Senior yet."} +

+ )} ); }; diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index b18b4cb6..6983941f 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -12,8 +12,11 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { UserContext } from "src/context/UserProvider"; import Logo from "@public/icons/logo.svg"; import Image from "next/image"; +<<<<<<< HEAD import { RoleAlias } from "@constants/RoleAlias"; import { fullName } from "@utils"; +======= +>>>>>>> 9bd5bd7 (finish first draft) interface Button { name: string; @@ -98,6 +101,7 @@ const Sidebar = (props: ISideBar) => {
<_Sidebar {...props} />
+<<<<<<< HEAD
setSidebarVisible(false)} @@ -119,6 +123,30 @@ const Sidebar = (props: ISideBar) => { <_Sidebar {...props} />
)} +======= + +
+ {/* TODO(nickbar01234) - Render university name */} + {/*
+
+ +
+ University +
+
+ Tufts University +
*/} +
+
+ {user.name ?? ""} +
+
+ {user.role[0] + user.role.toLowerCase().slice(1)} +
+ +>>>>>>> 9bd5bd7 (finish first draft)
); diff --git a/src/components/TileGrid/UserTile.tsx b/src/components/TileGrid/UserTile.tsx index 7a0a63df..f0616bc4 100644 --- a/src/components/TileGrid/UserTile.tsx +++ b/src/components/TileGrid/UserTile.tsx @@ -54,7 +54,7 @@ export function UserTile({

{student && student.name ? student.name + (student.admin ? " (Admin)" : "") - : senior && senior.name + : senior ? senior.name : null}

diff --git a/src/components/admin/DisplayChapter.tsx b/src/components/admin/DisplayChapter.tsx index 02eb66ec..d8b91205 100644 --- a/src/components/admin/DisplayChapter.tsx +++ b/src/components/admin/DisplayChapter.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/jsx-no-duplicate-props */ "use client"; import { editRole } from "@api/user/[uid]/edit-role/route.client";