Skip to content

Commit

Permalink
Merge branch 'main' into feature/simple-settings-page
Browse files Browse the repository at this point in the history
  • Loading branch information
JiashuHarryHuang committed Apr 27, 2024
2 parents a043aa3 + 9d4f604 commit 35932ab
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 1 deletion.
60 changes: 60 additions & 0 deletions components/Logs/LogsDashboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { DashboardContainer } from '@/styles/volunteerDashboard.styles';
import { useEffect, useState } from 'react';
import {
VolunteerLogData,
VolunteerEventData,
} from 'bookem-shared/src/types/database';
import LogsTable from './LogsTable';
import LogsStats from './LogsStats';
import { Greeting, Header } from '@/styles/dashboard.styles';
import { Card } from 'antd';

type VolunteerLogWithEvent = VolunteerLogData & {
event: VolunteerEventData;
};

export type LogTableData = VolunteerLogWithEvent & {
eventName: string;
};

// unpack the eventName from the event object so that it can be used as a column in the table
const processLogDataForTable = (
logData: VolunteerLogWithEvent[]
): LogTableData[] => {
return logData.map(log => {
return {
...log,
eventName: log.event.name,
};
});
};

export default function LogsDashboard() {
const [logData, setLogData] = useState<LogTableData[]>([]);

useEffect(() => {
const fetchLogs = async () => {
const response = await fetch('/api/volunteer-logs');
const data: VolunteerLogWithEvent[] = await response.json();
// console.log("Logs data: ", data);
setLogData(processLogDataForTable(data));
};
fetchLogs();
}, []);

console.log('Log data: ', logData);

return (
<DashboardContainer>
<Greeting>Your Logs</Greeting>
<LogsStats logData={logData} />
{/* Table of logs */}
<Header>Log Details:</Header>
<Card
// gray background
style={{ backgroundColor: '#f0f2f5' }}>
<LogsTable logData={logData} />
</Card>
</DashboardContainer>
);
}
65 changes: 65 additions & 0 deletions components/Logs/LogsStats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { LogTableData } from './LogsDashboard';
import { VolunteerStatsContainer } from '@/styles/volunteerDashboard.styles';
import {
Greeting,
StatsFlex,
FlexChild,
StatsNumber,
StatsDescription,
Header,
} from '@/styles/dashboard.styles';
import { VolunteerLogStatus } from 'bookem-shared/src/types/database';

// only count the approved logs
const calcTotalHours = (logData: LogTableData[]) => {
let totalHours = 0;
logData.forEach(log => {
if (log.status === VolunteerLogStatus.Approved) {
totalHours += log.hours;
}
});
return totalHours;
};

const calcTotalBooks = (logData: LogTableData[]) => {
let totalBooks = 0;
logData.forEach(log => {
if (log.status === VolunteerLogStatus.Approved) {
totalBooks += log.numBooks || 0;
}
});
return totalBooks;
};

// only count approved logs of events and only count unique events
const calcNumEvents = (logData: LogTableData[]) => {
const eventSet = new Set<string>();
logData.forEach(log => {
if (log.status === VolunteerLogStatus.Approved) {
eventSet.add(log.eventName);
}
});
return eventSet.size;
};

export default function LogsStats({ logData }) {
return (
<VolunteerStatsContainer>
<Header>Your accomplishments at a glance:</Header>
<StatsFlex>
<FlexChild>
<StatsNumber>{calcNumEvents(logData)}</StatsNumber>
<StatsDescription>Events helped</StatsDescription>
</FlexChild>
<FlexChild>
<StatsNumber>{calcTotalHours(logData)}</StatsNumber>
<StatsDescription>Hours volunteered</StatsDescription>
</FlexChild>
<FlexChild>
<StatsNumber>{calcTotalBooks(logData)}</StatsNumber>
<StatsDescription>Books distributed</StatsDescription>
</FlexChild>
</StatsFlex>
</VolunteerStatsContainer>
);
}
79 changes: 79 additions & 0 deletions components/Logs/LogsTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Table, Tag } from 'antd';
import { LogTableData } from './LogsDashboard';
import { VolunteerLogStatus } from 'bookem-shared/src/types/database';
import Link from 'next/link';
// use antd link icon
import { LinkOutlined } from '@ant-design/icons';

export default function LogsTable({ logData }: { logData: LogTableData[] }) {
const columns = [
{
title: 'Event',
dataIndex: 'eventName',
key: 'event',
},
// add a see event link
{
title: 'Event Details',
dataIndex: 'event',
key: 'seeEvent',
render: (event: any) => {
return (
<Link href={`/event/${event._id}`}>
{/* light blue color text */}
<div style={{ color: '#1890ff' }}>
<LinkOutlined /> See event
</div>
</Link>
);
},
},

{
title: 'Atended on',
dataIndex: 'date',
key: 'date',
render: (date: string) => {
return new Date(date).toLocaleDateString();
},
},
{
title: 'Log submitted on',
dataIndex: 'createdAt',
key: 'createdAt',
render: (createdAt: string) => {
return new Date(createdAt).toLocaleDateString();
},
},
{
title: 'Hours',
dataIndex: 'hours',
key: 'hours',
},
{
title: 'Books',
dataIndex: 'numBooks',
key: 'numBooks',
},
{
title: 'Status',
dataIndex: 'status',
key: 'status',
// render the status with tags of different colors
render: (status: string) => {
let color = 'blue';
if (status === VolunteerLogStatus.Approved) {
color = 'green';
} else if (status === VolunteerLogStatus.Rejected) {
color = 'red';
}
return <Tag color={color}>{status}</Tag>;
},
},
];

return (
// allow the table to scroll horizontally
<Table dataSource={logData} columns={columns} scroll={{ x: true }} />
);
}
2 changes: 1 addition & 1 deletion pages/api/volunteer-logs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export default async function handler(
// get all volunteerEvents from collection that match the user's Id
const volunteerLogs = await VolunteerLogs.find({
userId: usersId,
});
}).populate('event');

// return the result
res.status(200).json(volunteerLogs);
Expand Down
8 changes: 8 additions & 0 deletions pages/logs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import LogsDashboard from '@/components/Logs/LogsDashboard';

export default function Logs() {
return <LogsDashboard />;
}

// perform automatic redirection to login page if user not logged in.
export { getServerSideProps } from '@/lib/getServerSideProps';
13 changes: 13 additions & 0 deletions public/sidebar/logs-black.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions public/sidebar/logs-white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions styles/logs.style.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import styled from 'styled-components';

/**
* Container for volunteer dashboard
*/
export const DashboardContainer = styled.div`
height: fit-content;
width: 100%;
padding: 40px;
position: relative;
`;
9 changes: 9 additions & 0 deletions utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const AVAILABLE_ROUTES = {
HOME: '/',
VOLUNTEER: '/volunteer',
SETTINGS: '/settings',
LOGS: '/logs',
};

/**
Expand Down Expand Up @@ -75,6 +76,14 @@ export const SIDEBAR_ICON_PARAMS: SidebarIconParams[] = [
linkTo: AVAILABLE_ROUTES.HOME,
text: 'Home',
},
{
desktopDefaultSrc: '/sidebar/logs-white.svg',
mobileDefaultSrc: '/sidebar/logs-black.svg',
desktopHoveredSrc: '/sidebar/logs-black.svg',
mobileHoveredSrc: '/sidebar/logs-white.svg',
linkTo: '/logs',
text: 'Logs',
},
{
desktopDefaultSrc: '/sidebar/volunteer-white.png',
mobileDefaultSrc: '/sidebar/volunteer-black.png',
Expand Down

0 comments on commit 35932ab

Please sign in to comment.