Skip to content

Commit

Permalink
Display chapter request metadata (#174)
Browse files Browse the repository at this point in the history
* Display chapter request metadata

* Fix styling nits

* Fix missing duration

* Add vertical padding to dropdown container
  • Loading branch information
nickbar01234 authored Apr 28, 2024
1 parent cde0fb2 commit 06e5c8a
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 85 deletions.
1 change: 1 addition & 0 deletions src/app/private/admin/home/chapters/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const AdminChaptersPage = async () => {
const chapters = await prisma.chapter.findMany({
include: {
students: true,
chapterRequest: true,
},
});

Expand Down
1 change: 1 addition & 0 deletions src/app/private/admin/home/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const AdminHomePageWrapper = async () => {
const chapters = await prisma.chapter.findMany({
include: {
students: true,
chapterRequest: true,
},
});

Expand Down
36 changes: 31 additions & 5 deletions src/components/AdminHomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@

import { Prisma } from "@prisma/client";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faTrashCan } from "@fortawesome/free-solid-svg-icons";
import { faEllipsis, 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";
import ChapterRequest from "./ChapterRequest";
import DropDownContainer from "./container/DropDownContainer";

type ChapterWithUser = Prisma.ChapterGetPayload<{
include: { students: true };
type ChapterWithUserAndChapterRequest = Prisma.ChapterGetPayload<{
include: { students: true; chapterRequest: true };
}>;

type AdminHomePageProps = {
chapters: ChapterWithUser[];
chapters: ChapterWithUserAndChapterRequest[];
};

const AdminHomePage = ({ chapters }: AdminHomePageProps) => {
Expand Down Expand Up @@ -66,7 +68,31 @@ const AdminHomePage = ({ chapters }: AdminHomePageProps) => {
value: prez?.email ?? "",
},
]}
topRightButton={<TileEdit options={options} />}
topRightButton={
<TileEdit
options={options}
editIconProps={
<FontAwesomeIcon
className="fa-lg cursor-pointer"
icon={faEllipsis}
/>
}
/>
}
moreInformation={
<DropDownContainer defaultExpand={false}>
<ChapterRequest
chapterRequest={chapter.chapterRequest}
ContainerNode={({ children }) => (
<div className="flex h-fit w-full flex-col gap-y-4 bg-white">
{children}
</div>
)}
readonly
title=""
/>
</DropDownContainer>
}
/>
);
}}
Expand Down
96 changes: 56 additions & 40 deletions src/components/ChapterRequest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ChapterRequest } from "@prisma/client";
import { InfoTile } from "./TileGrid";
import { useApiThrottle } from "@hooks";
import { Spinner } from "./skeleton";
import DropDownContainer from "./container/DropDownContainer";

interface ChapterRequestMoreInformation {
question: string;
Expand All @@ -13,6 +14,9 @@ interface ChapterRequestMoreInformation {

interface ChapterRequestProps {
chapterRequest: ChapterRequest;
readonly?: boolean; // Defaults to false
ContainerNode?: ({ children }: { children?: React.ReactNode }) => JSX.Element;
title?: string;
}

const MoreInformation = (props: ChapterRequestMoreInformation) => {
Expand All @@ -26,7 +30,8 @@ const MoreInformation = (props: ChapterRequestMoreInformation) => {
};

const ChapterRequest = (props: ChapterRequestProps) => {
const { chapterRequest: request } = props;
const { chapterRequest: request, ContainerNode, title } = props;
const readonly = props.readonly ?? false;

const router = useRouter();

Expand Down Expand Up @@ -59,7 +64,7 @@ const ChapterRequest = (props: ChapterRequestProps) => {

return (
<InfoTile
title={request.university}
title={title ?? request.university}
information={[
{
key: "Requester",
Expand All @@ -78,46 +83,57 @@ const ChapterRequest = (props: ChapterRequestProps) => {
value: request.phoneNumber,
},
]}
ContainerNode={ContainerNode}
moreInformation={
<div className="flex flex-col gap-y-2">
{qas.map((question) => (
<MoreInformation key={question.question} {...question} />
))}
{!fetching ? (
<div className="mt-2 flex flex-row space-x-2">
<div
className="w-1/2 cursor-pointer rounded-xl bg-dark-teal py-1 text-center text-white hover:bg-[#1b4448]"
onClick={() =>
throttleChapterRequest({
body: {
chapterRequestId: request.id,
approved: true,
},
})
}
>
Accept
</div>
<div
className="w-1/2 cursor-pointer rounded-xl bg-sunset-orange py-1 text-center text-white hover:bg-[#ED5858]"
onClick={async () =>
throttleChapterRequest({
body: {
chapterRequestId: request.id,
approved: false,
},
})
}
>
Decline
</div>
readonly ? (
<div className="flex flex-col gap-y-2">
{qas.map((question) => (
<MoreInformation key={question.question} {...question} />
))}
</div>
) : (
<DropDownContainer defaultExpand={false} elementsClassName="pt-4">
<div className="flex flex-col gap-y-2">
{qas.map((question) => (
<MoreInformation key={question.question} {...question} />
))}
{!fetching ? (
<div className="mt-2 flex flex-row space-x-2">
<div
className="w-1/2 cursor-pointer rounded-xl bg-dark-teal py-1 text-center text-white hover:bg-[#1b4448]"
onClick={() =>
throttleChapterRequest({
body: {
chapterRequestId: request.id,
approved: true,
},
})
}
>
Accept
</div>
<div
className="w-1/2 cursor-pointer rounded-xl bg-sunset-orange py-1 text-center text-white hover:bg-[#ED5858]"
onClick={async () =>
throttleChapterRequest({
body: {
chapterRequestId: request.id,
approved: false,
},
})
}
>
Decline
</div>
</div>
) : (
<div className="flex justify-center p-2">
<Spinner height={16} width={16} />
</div>
)}
</div>
) : (
<div className="flex justify-center p-2">
<Spinner height={20} width={16} />
</div>
)}
</div>
</DropDownContainer>
)
}
/>
);
Expand Down
54 changes: 31 additions & 23 deletions src/components/TileGrid/InfoTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import Link from "next/link";
import React from "react";
import DropDownContainer from "@components/container/DropDownContainer";

interface Information {
key: string;
Expand All @@ -15,24 +14,19 @@ interface InfoTileProps {
topRightButton?: React.ReactNode;
moreInformation?: React.ReactNode;
href?: string;
ContainerNode?: ({ children }: { children?: React.ReactNode }) => JSX.Element;
defaultExpand?: boolean;
}

/**
* Displays a tile with the given information.
*
* @param information An array of key-value pairs. Each row of the tile display 2 information, as specified by the order
* in the array
* @param moreInformation If present, will display a "show more" option that expands on click
*/
const InfoTile = (params: InfoTileProps) => {
const { title, information, topRightButton, moreInformation, href } = params;
const _InfoTile = (props: Omit<InfoTileProps, "ContainerNode">) => {
const { title, information, topRightButton, moreInformation, href } = props;

return (
<div className="flex h-fit w-full flex-col gap-y-4 rounded-lg bg-white p-6 shadow-md shadow-gray-500">
<>
<div className="relative flex items-center justify-between">
<Link
href={href ?? ""}
className={`href ? "" : "cursor-default" truncate`}
className={href ? "" : "cursor-default truncate"}
>
<h1 className="text-2xl font-bold text-dark-teal">{title}</h1>
</Link>
Expand All @@ -49,17 +43,31 @@ const InfoTile = (params: InfoTileProps) => {
</div>
))}
</div>
{moreInformation ? (
<DropDownContainer
title={
<p className="mb-6 w-fit cursor-pointer text-dark-teal underline">
Show more
</p>
}
>
{moreInformation}
</DropDownContainer>
) : null}
{moreInformation ?? null}
</>
);
};

/**
* Displays a tile with the given information.
*
* @param information An array of key-value pairs. Each row of the tile display 2 information, as specified by the order
* in the array
* @param moreInformation If present, will display a "show more" option that expands on click
*/
const InfoTile = (props: InfoTileProps) => {
const { ContainerNode, ...other } = props;

if (ContainerNode != undefined) {
return (
<ContainerNode>
<_InfoTile {...other} />
</ContainerNode>
);
}
return (
<div className="flex h-fit w-full flex-col gap-y-4 rounded-lg bg-white p-6 shadow-lg">
<_InfoTile {...other} />
</div>
);
};
Expand Down
33 changes: 24 additions & 9 deletions src/components/container/DropDownContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,55 @@ import { faCaretDown, faCaretRight } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

interface DropDownContainerProps {
classname?: string;
containerClassName?: string;
elementsClassName?: string;
title?: React.ReactNode;
children?: React.ReactNode;
defaultExpand?: boolean;
}

const DropDownContainer = (props: DropDownContainerProps) => {
const [showItems, setShowItems] = React.useState(true);
const [showItems, setShowItems] = React.useState(props.defaultExpand ?? true);
const animationDivRef = React.useRef<HTMLDivElement>(null);

const handleClick = () => {
setShowItems(!showItems);
if (animationDivRef.current) {
// Prevent scroll bar from rendering
animationDivRef.current.style["overflow"] = "hidden";
}
};

return (
<div className={props.classname ?? ""}>
<div className={props.containerClassName ?? ""}>
<div className="flex cursor-pointer" onClick={handleClick}>
<div className="pr-2">
<FontAwesomeIcon
className="fa-fw"
icon={showItems ? faCaretDown : faCaretRight}
/>
</div>
{props.title}
{props.title ?? (
<p className="w-fit cursor-pointer text-dark-teal underline">
Show more
</p>
)}
</div>
<div
className={`overflow-auto ${
showItems ? "h-fit max-h-[512px] pb-4 md:max-h-[1024px]" : "max-h-0"
ref={animationDivRef}
className={`overflow-hidden py-2 ${
showItems ? "max-h-[512px] md:max-h-[1024px]" : "max-h-0"
}`}
style={
showItems
? { transition: "max-height 0.3s ease" }
: { transition: "max-height 0.1s ease" }
? { transition: "max-height 1s ease" }
: { transition: "max-height 0.3s ease" }
}
onTransitionEnd={(ref) =>
(ref.currentTarget.style["overflow"] = "auto")
}
>
{props.children}
<div className={props.elementsClassName ?? ""}>{props.children}</div>
</div>
</div>
);
Expand Down
9 changes: 1 addition & 8 deletions src/components/user/UserJoinRequest.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
"use client";

import { Prisma, UserRequest } from "@prisma/client";
import { TileEdit } from "../TileGrid/TileEdit";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faCheck,
faEllipsis,
faRotateLeft,
} from "@fortawesome/free-solid-svg-icons";
import {
handleJoinChapterRequest,
handleManageChapterRequest,
Expand Down Expand Up @@ -57,7 +50,7 @@ const UserJoinRequest = (props: UserJoinRequestProps) => {
fetchingHandleJoinChapterRequest || fetchingManageChapterRequest;

return (
<div className="flex h-full w-full flex-col gap-y-6 px-7 py-[104px]">
<div className="flex h-full w-full flex-col gap-y-6 py-[104px]">
<p className="text-center text-4xl"> Welcome To The Legacy Project</p>
<p className="text-2xl font-bold">Join a Chapter Below:</p>
<CardGrid
Expand Down

0 comments on commit 06e5c8a

Please sign in to comment.