Skip to content

Commit

Permalink
Merge pull request #289 from UoaWDCC/UABC-276-member-table
Browse files Browse the repository at this point in the history
Uabc 276 member table
  • Loading branch information
dyzhuu authored Oct 20, 2024
2 parents f806a3f + db8aad4 commit a6f1632
Show file tree
Hide file tree
Showing 12 changed files with 225 additions and 9 deletions.
1 change: 0 additions & 1 deletion src/app/(dev)/account/client-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { z } from "zod";
import { BackNavigationBar } from "@/components/BackNavigationBar";
import { TextInput } from "@/components/TextInput";
import { Button } from "@/components/ui/button";
// import { useRouter } from "next/router";
import { cn } from "@/lib/utils";
import type { PlayLevel } from "@/types/types";

Expand Down
23 changes: 23 additions & 0 deletions src/app/admin/member-approval/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { MemberApprovalTable } from "@/components/admin/members/MemberApprovalTable/MemberApprovalTable";
import { BackNavigationBar } from "@/components/BackNavigationBar";

export const metadata = {
title: "Member Approval - UABC Booking Portal",
};

export default function AdminMemberApprovalPage() {
return (
<div className="mx-4 flex min-h-dvh flex-col">
<BackNavigationBar title="Member Approval" pathName="/admin" />
<div className="flex grow flex-col items-center">
<div className="flex w-full flex-col gap-y-4 py-4 lg:mt-12 lg:w-4/5 lg:min-w-fit lg:px-12 lg:pt-10">
<h1 className="text-2xl font-semibold">Approve Members</h1>
<p className="text-muted-foreground">
Here&apos;s a list of members currently awaiting approval
</p>
<MemberApprovalTable />
</div>
</div>
</div>
);
}
9 changes: 3 additions & 6 deletions src/app/admin/members/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MemberApprovalTable } from "@/components/admin/members/MemberApprovalTable/MemberApprovalTable";
import { MemberManagementTable } from "@/components/admin/members/MemberManagementTable/MemberManagementTable";
import { BackNavigationBar } from "@/components/BackNavigationBar";

export const metadata = {
Expand All @@ -11,11 +11,8 @@ export default function AdminMembersPage() {
<BackNavigationBar title="Members" pathName="/admin" />
<div className="flex grow flex-col items-center">
<div className="flex w-full flex-col gap-y-4 py-4 lg:mt-12 lg:w-4/5 lg:min-w-fit lg:px-12 lg:pt-10">
<h1 className="text-2xl font-semibold">Approve Members</h1>
<p className="text-muted-foreground">
Here&apos;s a list of members currently awaiting approval
</p>
<MemberApprovalTable />
<h1 className="text-2xl font-semibold">Member Management</h1>
<MemberManagementTable />
</div>
</div>
</div>
Expand Down
7 changes: 5 additions & 2 deletions src/app/admin/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CalendarClock, CalendarDays } from "lucide-react";
import { CalendarClock, CalendarDays, Users } from "lucide-react";
import { BsPersonFillCheck } from "react-icons/bs";

import { DashboardButton } from "@/components/admin/DashboardButton";
Expand All @@ -25,8 +25,11 @@ export default async function AdminDashboardPage() {
Edit Semester Schedules
</DashboardButton>
<DashboardButton href="/admin/members" className="relative">
<Users size={24} className="min-w-6" /> Manage Members
</DashboardButton>
<DashboardButton href="/admin/member-approval" className="relative">
<MemberApprovalPing />
<BsPersonFillCheck size={24} className="min-w-6" /> Members
<BsPersonFillCheck size={24} className="min-w-6" /> Approve Members
</DashboardButton>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/app/api/users/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const GET = adminRouteWrapper(async (req) => {
firstName: true,
lastName: true,
email: true,
prepaidSessions: true,
},
limit: paginationParams.limit,
offset: paginationParams.offset,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"use client";

import { useMemo } from "react";
import {
getCoreRowModel,
getPaginationRowModel,
useReactTable,
} from "@tanstack/react-table";

import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { useMembers } from "@/hooks/query/useMembers";
import { columns } from "./columns";
import { MemberManagementTableRow } from "./MemberManagementTableRow";

export function MemberManagementTable({ className }: { className?: string }) {
const { data, isLoading } = useMembers();

const pendingMembers = useMemo(
() =>
data?.map((member) => {
return {
id: member.id,
name: `${member.firstName} ${member.lastName}`,
email: member.email,
prepaidSessions: member.prepaidSessions,
};
}),
[data]
);

const table = useReactTable({
data: pendingMembers ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
initialState: {
columnVisibility: {
id: false,
},
},
});

if (isLoading) {
return <div>Loading</div>;
}

return (
<div className="mb-10 rounded border">
<Table className={className}>
<TableHeader>
<TableRow>
<TableHead className="w-[200px]">Name</TableHead>
<TableHead className="lg:table-cell">Email</TableHead>
<TableHead className="w-[200px] text-center lg:table-cell">
Prepaid Sessions
</TableHead>
<TableHead className="w-[200px] text-center lg:table-cell">
Actions
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table
.getRowModel()
.rows.map((row) => (
<MemberManagementTableRow
key={row.getValue("id")}
userId={row.getValue("id")}
row={row}
/>
))
) : (
<TableRow>
<TableCell
colSpan={4}
className="h-24 text-center text-base font-medium text-tertiary/70"
>
No members found.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use client";

import type { Row } from "@tanstack/react-table";

import { Button } from "@/components/ui/button";
import { TableCell, TableRow } from "@/components/ui/table";
import type { Member } from "./columns";

interface MemberManagementTableRowProps {
row: Row<Member>;
userId: string;
}

export function MemberManagementTableRow({
row,
}: MemberManagementTableRowProps) {
const name: string = row.getValue("name");
const email: string = row.getValue("email");
const prepaidSessions: string = row.getValue("prepaidSessions");

return (
<TableRow>
<TableCell className="w-[75px] max-w-[125px] truncate sm:max-w-max">
{name}
</TableCell>
<TableCell className="min-w-[100px] max-w-[150px] truncate xs:table-cell sm:max-w-full">
{email}
</TableCell>
<TableCell className="min-w-[100px] max-w-[150px] text-center">
{prepaidSessions}
</TableCell>
<TableCell className="p-4 text-center">
<div className="flex h-10 items-center justify-center">
<Button className="h-6 w-12" variant="outline">
Edit
</Button>
</div>
</TableCell>
</TableRow>
);
}
28 changes: 28 additions & 0 deletions src/components/admin/members/MemberManagementTable/columns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { ColumnDef } from "@tanstack/react-table";

export type Member = {
id: string;
name: string;
email: string;
prepaidSessions: number;
};

export const columns: ColumnDef<Member>[] = [
{
accessorKey: "id",
header: "Id",
},
{
accessorKey: "name",
header: "Name",
},
{
accessorKey: "email",
header: "Email",
},
{
accessorKey: "prepaidSessions",
header: "Prepaid Sessions",

},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./MemberManagementTable";
27 changes: 27 additions & 0 deletions src/hooks/query/useMembers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useQuery } from "@tanstack/react-query";

import { QUERY_KEY } from "@/lib/utils/queryKeys";

export type MemberResponse = {
id: string;
firstName: string;
lastName: string;
email: string;
prepaidSessions: number;
};

const fetchMembers = async (): Promise<MemberResponse[]> => {
const response = await fetch(`/api/users?member=true&verified=true`, {
cache: "no-store",
});
return response.json();
};

export const useMembers = () => {
const query = useQuery({
queryKey: [QUERY_KEY.MEMBERS],
queryFn: fetchMembers,
});

return query;
};
1 change: 1 addition & 0 deletions src/hooks/query/usePendingMembers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ export const usePendingMembers = () => {

return query;
};

1 change: 1 addition & 0 deletions src/lib/utils/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export enum QUERY_KEY {
CURRENT_GAME_SESSIONS_ID = "current-game-sessions-id",
GAME_SESSION = "game-session",
PENDING_MEMBERS = "pending-members",
MEMBERS = "members",
SEMESTERS = "semesters",
SCHEDULES = "schedules",
ATTENDEES = "game-session-attendees",
Expand Down

0 comments on commit a6f1632

Please sign in to comment.