Skip to content

Commit

Permalink
Merge pull request #72 from ChangePlusPlusVandy/volunteer-logs
Browse files Browse the repository at this point in the history
Change input type for volunteer log popup; Work on rendering coluntee…
  • Loading branch information
JiashuHarryHuang authored Dec 4, 2023
2 parents 5d4d981 + 41cb862 commit 084e0ce
Show file tree
Hide file tree
Showing 10 changed files with 371 additions and 97 deletions.
69 changes: 37 additions & 32 deletions components/Forms/LogHoursPopupWindowForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,63 @@ import {
LargeFormInput,
LogHoursForm,
} from '@/styles/components/Forms/logHoursPopupWindowForm.styles';
import React from 'react';
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import PopupWindow from '@/components/shared/PopupWindow';
import WindowFlow from '@/components/shared/WindowFlow';
import VolunteerSignedEvents from '../Volunteer/VolunteerSignedEvents';
import { QueriedVolunteerEventData } from 'bookem-shared/src/types/database';

const LogHoursPopupWindowForm = ({
setShowPopup,
successMessage,
errorMessage,
}: {
setShowPopup: React.Dispatch<React.SetStateAction<boolean>>;
successMessage: (message: string) => void;
errorMessage: (message: string) => void;
}) => {
// get functions from react hook form
const { register, handleSubmit } = useForm();

const [selectedEvent, setSelectedEvent] =
useState<QueriedVolunteerEventData>();

// TODO: combine event and program into one so users only need to select event
// that they signed up for (which is automatically under a program)
const pages = ['Event', 'Program', 'Numbers', 'Comments'];
const pages = ['Event', 'Numbers', 'Comments'];

// handle form submission by parsing data and calling createVolunteerLog
const onSubmit = (data: any) => {
const results = JSON.stringify({
// event: data.Event,
eventId: selectedEvent?._id,
hours: parseInt(data.NumberOfHours),
date: data.DateOfVisit,
feedback: data.Comment,
numBooks: data.NumberOfBooks,
});
console.log(results);
createVolunteerLog(results);
};

// sends a post request to insert the volunteer form
const createVolunteerLog = async (data: any) => {
// TODO: implement endpoint for VolunteerEventApplication and call it
await fetch('/api/volunteerLogs/create', {
method: 'POST',
body: data,
});
try {
// Implement endpoint for VolunteerEventApplication and call it
const response = await fetch('/api/volunteerLogs/create', {
method: 'POST',
body: data,
});
if (response.status === 200) {
const message = (await response.json()).message;
setShowPopup(false);
successMessage(message);
} else {
const message = (await response.json()).message;
errorMessage(message);
}
} catch (err) {
errorMessage('Sorry an error occurred');
}
};

return (
Expand All @@ -52,29 +72,14 @@ const LogHoursPopupWindowForm = ({
components={[
// Page 1 - Event
<LogHoursForm key={pages[0]}>
TODO: show events volunteer signed up for
<VolunteerSignedEvents
selectedEvent={selectedEvent}
setSelectedEvent={setSelectedEvent}
/>
</LogHoursForm>,

// Page 2 - Program
// TODO: remove this
// Page 2 - Numbers
<LogHoursForm key={pages[1]}>
<FormHeader>Please select one program</FormHeader>
<FormLabel>
<input {...register('Program')} type="radio" value="RIF" />
Reading is Fundamental (RIF)
</FormLabel>
<FormLabel>
<input {...register('Program')} type="radio" value="RFR" />
Ready for Reading (RFR)
</FormLabel>
<FormLabel>
<input {...register('Program')} type="radio" value="BFNK" />
Books for Nashville Kids (BFNK)
</FormLabel>
</LogHoursForm>,

// Page 3 - Numbers
<LogHoursForm key={pages[2]}>
<FormLabel>
{/* TODO: Add an icon here to display tool tip */}
Please log your volunteer hours <br /> (rounded to the nearest
Expand All @@ -90,7 +95,7 @@ const LogHoursPopupWindowForm = ({
<FormLabel>Date of visit</FormLabel>
<FormInput
{...register('DateOfVisit')}
type="text"
type="date"
placeholder="MM/DD/YYYY"
pattern="^((0|1)\d{1})\/((0|1|2)\d{1})\/((19|20)\d{2})"
title="Input must be in MM/DD/YYYY format"
Expand All @@ -107,8 +112,8 @@ const LogHoursPopupWindowForm = ({
/>
</LogHoursForm>,

// Page 4 - Comments
<LogHoursForm key={pages[3]}>
// Page 3 - Comments
<LogHoursForm key={pages[2]}>
<FormLabel>Anything else you&apos;d like to share?</FormLabel>
<LargeFormInput
{...register('Comment')}
Expand Down
29 changes: 28 additions & 1 deletion components/Volunteer/VolunteerDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { Media } from '@/lib/media';
import { BOOKEM_THEME } from '@/utils/constants';
import { QueriedUserData } from 'bookem-shared/src/types/database';
import { formatDate } from '@/utils/utils';
import { message } from 'antd';

const VolunteerDashboard = ({
userData,
Expand All @@ -29,12 +30,38 @@ const VolunteerDashboard = ({
}) => {
// set pop up window to false
const [showPopup, setShowPopup] = useState(false);
const [messageApi, contextHolder] = message.useMessage();

// Display success message
const successMessage = (message: string) => {
messageApi.open({
type: 'success',
content: message,
});
};

// Display error message
const errorMessage = (message: string) => {
messageApi.open({
type: 'error',
content: message,
});
};

return (
<>
<DashboardContainer>
{/* Context for antd messages */}
{contextHolder}

{/* based on whether or not hideppopup is true, displays popup */}
{showPopup && <LogHoursPopupWindowForm setShowPopup={setShowPopup} />}
{showPopup && (
<LogHoursPopupWindowForm
successMessage={successMessage}
errorMessage={errorMessage}
setShowPopup={setShowPopup}
/>
)}

<Greeting>Volunteer</Greeting>

Expand Down
55 changes: 55 additions & 0 deletions components/Volunteer/VolunteerSignedEvents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React, { useEffect, useState } from 'react';
import { QueriedVolunteerEventData } from 'bookem-shared/src/types/database';
import { fetchData } from '@/utils/utils';
import { MainContainer } from '@/styles/volunteerHistory.styles';
import SelectableLongEventCard from '../shared/SelectableLongEventCard';

/**
* format horizontal upcoming event scroll bar on home page
*/
const VolunteerSignedEvents = ({
selectedEvent,
setSelectedEvent,
}: {
selectedEvent: QueriedVolunteerEventData | undefined;
setSelectedEvent: React.Dispatch<
React.SetStateAction<QueriedVolunteerEventData | undefined>
>;
}) => {
const [events, setEvents] = useState<QueriedVolunteerEventData[]>();
const [error, setError] = useState<Error>();

const handleEventClick = (event: QueriedVolunteerEventData) => {
// Update the selected event when an event is clicked
setSelectedEvent(event);
};

// Fetch upcoming events when rendered
useEffect(() => {
fetchData('/api/events/log-hour')
.then(data => setEvents(data))
.catch(err => setError(err));
}, []);
return (
<>
{/* TODO: render 404 page */}
{error && <>404 Event not found!</>}
{!events && !error && <div>Loading...</div>}
{events && (
<MainContainer>
{/* Loop through each VolunteerEvent specific to that user */}
{events.map(event => (
<SelectableLongEventCard
eventData={event}
key={event._id.toString()}
isSelected={selectedEvent === event}
onClick={() => handleEventClick(event)}
/>
))}
</MainContainer>
)}
</>
);
};

export default VolunteerSignedEvents;
17 changes: 1 addition & 16 deletions components/shared/LongEventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,7 @@ import {
} from '@/styles/components/longEventCard.styles';
import { QueriedVolunteerEventData } from 'bookem-shared/src/types/database';
import { convertLocationToString } from 'bookem-shared/src/utils/utils';

/**
* Helper function to format the time into a readable AM/PM format.
*
* Takes in an unformatted time and returns a formatted one.
*/
const formatAMPM = (date: { getHours: () => any; getMinutes: () => any }) => {
var hours = date.getHours();
var minutes = date.getMinutes();
var ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
minutes = minutes < 10 ? '0' + minutes : minutes;
var strTime = hours + ':' + minutes + ' ' + ampm;
return strTime;
};
import { formatAMPM } from '@/utils/utils';

// this component takes in and displays all of an event's data
const LongEventCard = ({
Expand Down
103 changes: 103 additions & 0 deletions components/shared/SelectableLongEventCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React from 'react';
import Image from 'next/image';
import {
EventImage,
Name,
AddressContainer,
AddressIcon,
InfoContainer,
Description,
ClockIcon,
Address,
CalendarIcon,
CheckmarkIcon,
Container,
} from '@/styles/components/longEventCard.styles';
import { QueriedVolunteerEventData } from 'bookem-shared/src/types/database';
import { convertLocationToString } from 'bookem-shared/src/utils/utils';
import { formatAMPM } from '@/utils/utils';

// this component takes in and displays all of an event's data
const SelectableLongEventCard = ({
eventData,
isSelected,
onClick,
}: {
eventData: QueriedVolunteerEventData;
isSelected: boolean;
onClick: () => void;
}) => {
// create a date object with JavaScript's Date constructor
const date = new Date(eventData.startDate);

return (
<Container
style={{
// Add styles for selected event
border: isSelected ? '2px solid blue' : '1px solid #ddd',
padding: '10px',
cursor: 'pointer',
}}
onClick={onClick}>
<EventImage>
<Image
src="/eventCard/event-image.png"
alt="Event image icon"
width={`${Math.round((300 / 328) * 53)}`}
height={`${Math.round((300 / 328) * 53)}`}
/>
</EventImage>
<Name>{eventData.name}</Name>

<AddressContainer>
<AddressIcon>
<Image
src="/eventCard/map.png"
alt="Map icon"
width={`${Math.round((300 / 328) * 21)}`}
height={`${Math.round((300 / 328) * 23.99)}`}
/>
</AddressIcon>
<Address>{convertLocationToString(eventData.location)}</Address>
</AddressContainer>

<InfoContainer>
<CalendarIcon>
<Image
src="/event/calendar.png"
alt="Calendar icon"
width={`${Math.round((300 / 328) * 21)}`}
height={`${Math.round((300 / 328) * 23.99)}`}
/>
{/* calls a JavaScript method to format the date into a readable format */}
<Description>{date.toDateString()}</Description>
</CalendarIcon>

<ClockIcon>
<Image
src="/event/clock.png"
alt="Clock icon"
width={`${Math.round((300 / 328) * 21.27)}`}
height={`${Math.round((300 / 328) * 22.14)}`}
/>
<Description>{formatAMPM(date)}</Description>
</ClockIcon>

<CheckmarkIcon>
<Image
src="/eventCard/checkmark.png"
alt="Checkmark icon"
width={`${Math.round((300 / 328) * 21)}`}
height={`${Math.round((300 / 328) * 23.99)}`}
/>
<Description>
{/* TODO: add data for number of books distributed*/}X books
distributed
</Description>
</CheckmarkIcon>
</InfoContainer>
</Container>
);
};

export default SelectableLongEventCard;
1 change: 1 addition & 0 deletions pages/api/events/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default async function handler(
// get all volunteerEvents from collection that match the user's Id
// sorted in descending order
const user = await Users.findById(session.user._id);

if (!user) {
return res.status(404).json({ message: 'User not found' });
}
Expand Down
Loading

1 comment on commit 084e0ce

@vercel
Copy link

@vercel vercel bot commented on 084e0ce Dec 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

bookem-user – ./

bookem-user-bookem-user.vercel.app
bookem-user.vercel.app
bookem-user-git-main-bookem-user.vercel.app

Please sign in to comment.