Skip to content

Commit

Permalink
Merge pull request #58 from Cassianky/events
Browse files Browse the repository at this point in the history
Event Page (Attendance)
  • Loading branch information
woowenjun99 authored Mar 19, 2023
2 parents ddb012f + 664f256 commit 43ee5c6
Show file tree
Hide file tree
Showing 11 changed files with 385 additions and 29 deletions.
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Note that not all variables here might be in use for your selected configuration
# When adding additional env variables, the schema in /env/schema.mjs should be updated accordingly
# When adding additional env variables, the schema in /env/schema.mjs should be
# updated accordingly. Please do not upload any environment variables here!!!

# Prisma
DATABASE_URL=
# DATABASE_URL=

# Next Auth
NEXTAUTH_SECRET=
Expand Down
182 changes: 182 additions & 0 deletions src/components/attendance/DataTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import * as React from 'react'
import {
Table,
Thead,
Tbody,
Tr,
Th,
Td,
chakra,
Box,
Icon,
} from '@chakra-ui/react'
import { BsArrowDownUp, BsChevronDown, BsChevronUp } from 'react-icons/bs'
import {
useReactTable,
flexRender,
getCoreRowModel,
ColumnDef,
SortingState,
getSortedRowModel,
} from '@tanstack/react-table'

export type DataTableProps<Data extends object> = {
data: Data[]
columns: ColumnDef<Data, any>[]
}

export function DataTable<Data extends object>({
data,
columns,
}: DataTableProps<Data>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
state: {
sorting,
},
})

return (
<Box
overflowY="auto"
maxHeight="60vh"
borderTop="3px solid #002D70"
borderBottom="3px solid #002D70"
sx={{
'&::-webkit-scrollbar': {
width: '15px',
outline: '3px solid #002D70',
},
'&::-webkit-scrollbar-thumb': {
backgroundColor: `#004B90`,
borderRadius: '20px',
border: '5px solid transparent',
backgroundClip: 'content-box',
},
}}
>
<Table>
<Thead>
{table.getHeaderGroups().map((headerGroup) => (
<Tr key={headerGroup.id}>
<Th
color="white"
bgColor="#01003D"
fontSize={{ base: '10px', md: '16px', lg: '20px' }}
py={5}
px={{ base: '2px', md: '6px', lg: '10px' }}
textTransform="capitalize"
textAlign="center"
borderX="3px solid #002D70"
borderY="none"
fontWeight={600}
position="sticky"
zIndex={1}
top={0}
>
Number
</Th>
{headerGroup.headers.map((header) => {
// see https://tanstack.com/table/v8/docs/api/core/column-def#meta to type this correctly
const meta: any = header.column.columnDef.meta
return (
<Th
color="white"
bgColor="#01003D"
fontSize={{ base: '10px', md: '16px', lg: '20px' }}
py={5}
px={{ base: '2px', md: '6px', lg: '10px' }}
textTransform="capitalize"
textAlign="center"
borderX="3px solid #002D70"
borderY="none"
position="sticky"
zIndex={1}
top={0}
key={header.id}
onClick={header.column.getToggleSortingHandler()}
isNumeric={meta?.isNumeric}
>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}

<chakra.span pl="4">
{header.column.getIsSorted() ? (
header.column.getIsSorted() === 'desc' ? (
<Icon
className="hover:cursor-pointer"
aria-label="sorted descending"
color="#F9813E"
style={{ strokeWidth: '1.5' }}
as={BsChevronDown}
/>
) : (
<Icon
className="hover:cursor-pointer"
aria-label="sorted descending"
color="#F9813E"
style={{ strokeWidth: '1.5' }}
as={BsChevronUp}
/>
)
) : (
<Icon
className="hover:cursor-pointer"
color="#F9813E"
style={{ strokeWidth: '1.5' }}
as={BsArrowDownUp}
/>
)}
</chakra.span>
</Th>
)
})}
</Tr>
))}
</Thead>
<Tbody>
{table.getRowModel().rows.map((row) => (
<Tr key={row.id}>
<Td
py={5}
px={{ base: '2px', md: '6px', lg: '10px' }}
fontSize={{ base: '10px', md: '16px', lg: '20px' }}
textAlign="center"
borderX="3px solid #002D70"
borderY="none"
fontWeight={600}
>
{parseInt(row.id, 10) + 1}
</Td>
{row.getVisibleCells().map((cell) => {
const meta: any = cell.column.columnDef.meta
return (
<Td
py={5}
px={{ base: '2px', md: '6px', lg: '10px' }}
fontSize={{ base: '10px', md: '16px', lg: '20px' }}
textAlign="center"
borderX="3px solid #002D70"
borderY="none"
fontWeight={600}
key={cell.id}
isNumeric={meta?.isNumeric}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</Td>
)
})}
</Tr>
))}
</Tbody>
</Table>
</Box>
)
}
3 changes: 2 additions & 1 deletion src/components/common/HamburgerNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { trpc } from '../../utils/trpc'
const navigation = [
{ name: 'Home', href: '/', current: true },
{ name: 'User', href: '/users', current: false },
{ name: 'Events', href: '/events/create', current: false },
{ name: 'Events', href: '/events', current: false },
{ name: 'Attendance', href: '/events/attendance', current: false },
{ name: 'Sign Out', href: '/api/auth/signout', current: false },
]

Expand Down
2 changes: 1 addition & 1 deletion src/components/common/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ type TabProps = {
const TabConfig: TabProps[] = [
{ name: 'Home', href: '/' },
{ name: 'User', href: '/users' },
{ name: 'Events', href: '/events/create' },
{ name: 'Events', href: '/events' },
{ name: 'Profile', href: '/profile' },
{ name: 'Sign Out', href: '/api/auth/signout' },
]
12 changes: 12 additions & 0 deletions src/config/ChakraTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,17 @@ export const theme: ThemeConfig = extendTheme({
onPrimaryContainer: '#FFFFFF',
},
},
progress: {
50: '#002D70',
100: '#002D70',
200: '#002D70',
300: '#002D70',
400: '#002D70',
500: '#002D70',
600: '#002D70',
700: '#002D70',
800: '#002D70',
900: '#002D70',
},
},
})
123 changes: 123 additions & 0 deletions src/pages/events/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { VStack, Button, Progress, useBreakpointValue } from '@chakra-ui/react'
import { DataTable } from '~/components/attendance/DataTable'
import { trpc } from '~/utils/trpc'
import React from 'react'
import Head from 'next/head'
import { useRouter } from 'next/router'
import { createColumnHelper } from '@tanstack/react-table'
import { AddIcon } from '@chakra-ui/icons'
import { useState } from 'react'
import TopNavbar from '~/components/common/TopNavbar'

const AttendancePage = () => {
const router = useRouter()
const isSmallScreen = useBreakpointValue({ base: true, md: false })
const [eventInfoData, setEventInfoData] = useState<eventInfos[]>([])

trpc.attendance.getAllAttendance.useQuery(undefined, {
onSuccess: (data: eventInfos[]) => setEventInfoData(data),
})

type eventInfos = {
number: string
name: string
total_users: string
total_attendees: string
startDate: string
endDate: string
}

const columnHelper = createColumnHelper<eventInfos>()

const columns = [
columnHelper.accessor('name', {
cell: (info) => info.getValue(),
header: 'Name',
}),
columnHelper.accessor('startDate', {
cell: (info) => {
const date = new Date(info.getValue().toString())
const formattedDate = date.toLocaleDateString('en-GB')
return formattedDate
},
header: 'Start Date',
}),
columnHelper.accessor('endDate', {
cell: (info) => {
const date = new Date(info.getValue().toString())
const formattedDate = date.toLocaleDateString('en-GB')
return formattedDate
},
header: 'End Date',
}),
columnHelper.accessor(
(row) => ({
total_attendees: row.total_attendees,
total_users: row.total_users,
}),
{
cell: (info) => {
return (
<div>
<p className="mb-2">
{info.getValue().total_attendees.toString()}/
{info.getValue().total_users.toString()}
</p>
<Progress
rounded="md"
background="#4365DD"
colorScheme="progress"
value={
(Number(info.getValue().total_attendees.toString()) /
Number(info.getValue().total_users.toString())) *
100
}
></Progress>
</div>
)
},
header: 'Attendance',
}
),
]

return (
<>
<Head>
<title>Attendance</title>
<link rel="icon" href="/favicon.ico" />
<meta name="description" content="The attendance page for Atlas" />
</Head>
<TopNavbar />
<div className="px-2 sm:px-6 sm:pt-5 md:px-20 md:pt-5 lg:px-28 lg:pt-5">
<h1 className="mb-10 text-center text-2xl font-bold">Attendance</h1>
<VStack align="left" className="mb-10">
{isSmallScreen ? (
<Button
bgColor="#97AEFF"
width={45}
className="mb-10 text-black"
borderRadius="full"
fontSize={15}
onClick={() => router.push('/events/create')}
>
<AddIcon />
</Button>
) : (
<Button
bgColor="#97AEFF"
width={215}
className="mb-10 text-black"
onClick={() => router.push('/events/create')}
>
Create Event
</Button>
)}
<DataTable columns={columns} data={eventInfoData} />
</VStack>
</div>
</>
)
}

export default AttendancePage
8 changes: 3 additions & 5 deletions src/pages/profile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { Box, Text, useToast } from '@chakra-ui/react'
import { Box, Text } from '@chakra-ui/react'
import { useSession } from 'next-auth/react'
import { trpc } from '~/utils/trpc'
import Head from 'next/head'
import { useRouter } from 'next/router'
import HamburgerNavbar from '~/components/common/HamburgerNavbar'
import LoadingScreen from '~/components/common/LoadingScreen'
import TopNavbar from '~/components/common/TopNavbar'
import ProfileGrid from '~/components/profile/ProfileGrid'

const ProfilePage = () => {
Expand All @@ -19,7 +17,7 @@ const ProfilePage = () => {
<link rel="icon" href="/favicon.ico" />
<meta name="description" content="The profile page for Atlas" />
</Head>
<HamburgerNavbar />
<TopNavbar />
<Box className="flex flex-col">
<Text className="m-8 text-center text-3xl font-semibold underline underline-offset-8">
Profile
Expand Down
2 changes: 2 additions & 0 deletions src/server/trpc/router/_app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { memberRouter } from './member'
import { profileRouter } from './profile'
import { userRouter } from './admin/users'
import { eventRouter } from './admin/events'
import { attendanceRouter } from './admin/attendance'

export const appRouter = router({
auth: authRouter,
Expand All @@ -13,6 +14,7 @@ export const appRouter = router({
member: memberRouter,
profile: profileRouter,
user: userRouter,
attendance: attendanceRouter,
})

export type AppRouter = typeof appRouter
Loading

0 comments on commit 43ee5c6

Please sign in to comment.