Skip to content

Commit

Permalink
Merge pull request #149 from Blueprint-Boulder/UpdateVendorPage
Browse files Browse the repository at this point in the history
Update vendor page
  • Loading branch information
nh602 authored Aug 24, 2024
2 parents afd6851 + fdfc241 commit db0775e
Show file tree
Hide file tree
Showing 16 changed files with 516 additions and 140 deletions.
42 changes: 32 additions & 10 deletions backend/controllers/EventController.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,39 @@ const {hash, genSalt} = require('bcryptjs');
const bcrypt = require('bcryptjs');

const getAllEvents = async (req, res, next) => {
try {
const events = await db.manyOrNone('SELECT * FROM Events');
if (events.length) {
res.locals.data = events;
next();
} else {
res.status(404).json({message: 'No events found'});
// If vendorId is non-null, return only events that the vendor is attending
const vendorId = req.query.vendorId;

// The query to use if vendorId !== null
const vendor_querystr = `SELECT E.* FROM Events AS E \
LEFT JOIN EventRequests AS R ON E.event_id = R.event_id \
WHERE R.vendor_id = $1 AND R.approved = true`;

let events = undefined;

// Execute query
if(vendorId){
try {
events = await db.manyOrNone(vendor_querystr, vendorId);
} catch (error) {
console.error(error);
res.status(500).json({error: 'Failed to retrieve events for vendor.'});
}
} catch (error) {
console.error(error);
res.status(500).json({error: 'Internal Server Error'});
} else {
try {
events = await db.manyOrNone("SELECT * FROM Events");
} catch (error) {
console.error(error);
res.status(500).json({error: 'Failed to retrieve events.'});
}
}

// Check the number of events returned
if (events.length) {
res.locals.data = events;
next();
} else {
res.status(404).json({message: 'No events found'});
}
};

Expand Down
30 changes: 30 additions & 0 deletions frontend/src/components/AttendingEvents.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, {useState, useContext, useEffect} from 'react';
import {Context} from '../services/context';
import LeavingPageIcon from '../components/LeavingPageIcon';

export default function AttendingEvents({vendorId, vendorService}){
const [events, setEvents] = useState([]);

// Parses the start / end time to a human readable format
const timeFormat = new Intl.DateTimeFormat('en', {
timeStyle: 'short',
dateStyle: 'short',
});

useEffect(() => {
(async () => {
setEvents(await vendorService.getVendorEvents(vendorId));
})();
}, [vendorId, vendorService]);

return <table className='w-full my-2'><tbody>
{
events !== undefined ? events.map((event) => {
return <tr className='border-b border-black border-opacity-30'>
<td><a className='py-1 flex flex-row justify-around' href={`/events/${event.event_id}`}><p>{event.name}</p><LeavingPageIcon/></a></td>
<td align='right' className='py-1 content-end'>{timeFormat.format(Date.parse(event.starttime))}</td>
</tr>
}) : <></>
}
</tbody></table>
}
28 changes: 20 additions & 8 deletions frontend/src/components/EventVendorsDisplay.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,33 @@ import React from 'react';
import VendorEventCard from './VendorEventCard';


export default function EventVendorsDisplay({showApproved, requests, vendors, eventService}) {
export default function EventVendorsDisplay({user, showApproved, requests, vendors, eventService}) {
console.log('EventVendorsDisplay Debug info: ', {
showApproved,
requests,
vendors,
eventService,
user
});

const createCardsAdmin = (reqs) => {
// console.log('create cards admin');
return reqs.map((req) => {
// console.log('Request:', req);
// console.log('Vendors:', vendors);

// No vendors have requested to attend this event
if (vendors.length === 0) return <></>;

// Returning approved only - The request was not approved
if (showApproved === true && req.approved !== true) return <></>;
if (showApproved === false && ( req.approved !== null || req.approved !== false) ) return <></>;


// Returning pending only - The request is not pending
if (showApproved === false && ( req.approved !== null ) ) return <></>;

// Fetch the vendor's profile
const res = vendors.filter((v) => v.id === req.vendorId)[0];
// console.log('Vendor:', res);
if (!res) {
console.error("Vendor's id not found - even though it should have been.");
return <></>;
}

// Return the card
return <VendorEventCard key={res.id} vendor={res} request={req} eventService={eventService}></VendorEventCard>;
Expand All @@ -32,7 +44,7 @@ export default function EventVendorsDisplay({showApproved, requests, vendors, ev

return <div className='flex flex-wrap p-5 gap-4 justify-center'>
{
requests.length > 0 ? createCardsAdmin(requests) : createCards(vendors)
user && user.isadmin ? createCardsAdmin(requests) : createCards(vendors)
}
</div>;
}
19 changes: 19 additions & 0 deletions frontend/src/components/LeavingPageIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';

export default function LeavingPageIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
shape-rendering="geometricPrecision"
text-rendering="geometricPrecision"
image-rendering="optimizeQuality"
fill-rule="evenodd"
clip-rule="evenodd"
viewBox="0 0 509 511.54"
aria-label="Leaving Page Icon"
width={"1rem"}
>
<path fill-rule="nonzero" d="M447.19 347.03c0-17.06 13.85-30.91 30.91-30.91 17.05 0 30.9 13.85 30.9 30.91v87.82c0 21.08-8.63 40.29-22.51 54.18-13.88 13.88-33.09 22.51-54.18 22.51H76.69c-21.09 0-40.3-8.63-54.18-22.51C8.63 475.14 0 455.93 0 434.85V76.69c0-21.09 8.63-40.3 22.51-54.18C36.39 8.63 55.6 0 76.69 0h86.98c17.06 0 30.9 13.85 30.9 30.9 0 17.06-13.84 30.91-30.9 30.91H76.69c-4.07 0-7.82 1.69-10.51 4.37-2.68 2.69-4.37 6.44-4.37 10.51v358.16c0 4.06 1.69 7.82 4.37 10.5 2.69 2.68 6.44 4.38 10.51 4.38h355.62c4.07 0 7.82-1.7 10.51-4.38 2.68-2.68 4.37-6.44 4.37-10.5v-87.82zm0-243.56L308.15 244.28c-11.91 12.12-31.45 12.28-43.56.37-12.11-11.91-12.28-31.45-.37-43.56L401.77 61.81H309.7c-17.06 0-30.9-13.85-30.9-30.91 0-17.05 13.84-30.9 30.9-30.9h168.4C495.15 0 509 13.85 509 30.9v165.04c0 17.06-13.85 30.9-30.9 30.9-17.06 0-30.91-13.84-30.91-30.9v-92.47z"/>
</svg>
);
}
2 changes: 1 addition & 1 deletion frontend/src/components/VendorEventCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default function VendorEventCard({vendor, request, eventService}) {
// console.log('vendvend', vendor);

return (
<div className='flex flex-col px-7 py-8 basis-2/5 gap-4 items-center bg-slate-50 rounded-lg drop-shadow-lg'>
<div className='flex flex-col px-7 py-8 basis-2/5 gap-4 items-center bg-greywhite rounded-lg drop-shadow-lg'>
<img src={vendor.image ? `/profilepics/${vendor.image}` : '/profile.webp'} onClick={()=> navigate(`/vendors/${vendor.id}`)}></img>
<p className='text-center'>{vendor.name}</p>
{
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/footer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default function Footer() {
const {user} = useContext(Context);

return (
<div className="fixed bottom-0 " id="Footer">
<div className="flex flex-row w-full h-fit fixed bottom-0 bg-cambridge" id="Footer">
<div id="Footer-content" className="flex justify-around items-center p-4">
<div className="footer-section">
<Link to="/events" className="text-blue-500">
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/routes/event.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default function Event({eventService, vendorService}) {
const [event, setEvent] = useState(null);
const navigate = useNavigate();
const {eventId} = useParams();

const {user, setMessage, setBad} = useContext(Context);

const [requests, setRequests] = useState([]);
Expand Down Expand Up @@ -143,7 +144,7 @@ export default function Event({eventService, vendorService}) {
return (<>
{showEditModal && <EditEventModal event={event} eventService={eventService} setShowEditModal={setShowEditModal} />}
<div id="Event-content" className="overflow-y-scroll w-full h-full flex flex-col gap-6 items-center py-2">
<div className='flex flex-row gap-4 px-10 py-6 bg-white w-10/12 rounded-md drop-shadow-md items-center'>
<div className='flex flex-row gap-4 px-10 py-6 bg-greywhite w-10/12 rounded-md drop-shadow-md items-center'>
<img src={bLogo} alt="Event Logo" className="w-1/3 basis-1/3 bg-clip-padding bg-white drop-shadow-xl rounded-xl" />
<div className='flex flex-col gap-1 basis-2/3 w-2/3'>
<div className={`flex flex-row ${loggedUser && loggedUser.isadmin ? 'justify-between' : 'justify-left'}`}>
Expand All @@ -161,7 +162,7 @@ export default function Event({eventService, vendorService}) {
</div>
</div>
{
description && <div className='flex flex-row justify-left gap-3 bg-white w-10/12 rounded-md drop-shadow-lg p-10'>
description && <div className='flex flex-row justify-left gap-3 bg-greywhite w-10/12 rounded-md drop-shadow-lg p-10'>
<p className='text-slate-500 font-semibold'>Description</p>
<p>{description}</p>
</div>
Expand All @@ -173,15 +174,15 @@ export default function Event({eventService, vendorService}) {
>Register</button> : <></>
}
<div className='flex flex-col gap-3 items-center'>
<p className='text-2xl font-bold'>{showApproved ? 'Attending Vendors' : 'Pending Requests'} ({showApproved ? vendors.length : requests.filter((req) => !req.approved).length})</p>
<p className='text-2xl font-bold'>{showApproved ? 'Attending Vendors' : 'Pending Requests'} ({showApproved ? user && user.isadmin ? requests.filter((req) => req.approved).length : vendors.length : requests.filter((req) => !req.approved).length})</p>
{
user && user.isadmin && <button className={`${adminButtonClasses} px-5 py-2 w-4/6`}
onClick={() => {
setShowApproved(!showApproved);
}}>Show {showApproved ? 'Pending' : 'Attending'}</button>
}
</div>
<EventVendorsDisplay showApproved={showApproved} vendors={vendors} requests={requests} eventService={eventService}></EventVendorsDisplay>
<EventVendorsDisplay user={user} showApproved={showApproved} vendors={vendors} requests={requests} eventService={eventService}></EventVendorsDisplay>
<FooterPad />
</div>
</>
Expand Down
42 changes: 23 additions & 19 deletions frontend/src/routes/events.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,25 +136,28 @@ export default function Events({eventService}) {
const end = new Date(`${event.endDate} ${event.endtime}`);

return (
<div className="bg-white shadow-lg right-0 left-0 rounded-lg p-4 max-w-sm ml-4 mr-4 bm-4">
<div className="mt-2">
<div className="text-lg font-semibold text-gray-900">{event.name}</div>
<div className="text-grey-5">{event.description}</div>
<div className="mt-3 text-grey-5">
{event.date}{start.toLocaleTimeString('en-US', {timeStyle: 'short'})} - {end.toLocaleTimeString('en-US', {timeStyle: 'short'})}
</div>
<div className="mt-1 text-sm text-grey-5 relative">
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 inline-block mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 2C8.13401 2 5 5.13401 5 9C5 14.25 12 22 12 22C12 22 19 14.25 19 9C19 5.13401 15.866 2 12 2ZM12 11C10.3431 11 9 9.65685 9 8C9 6.34315 10.3431 5 12 5C13.6569 5 15 6.34315 15 8C15 9.65685 13.6569 11 12 11Z" />
</svg>
{event.location}
</div>
<Link to={`/events/${event.eventId}`} className="mt-2 text-blue p-2 rounded-md inline-block">
<div className="flex flex-col gap-2 bg-greywhite text-grey-5 shadow-lg rounded-lg p-4 max-w-sm mx-4">
<div className="text-lg font-bold text-gray-900">{event.name}</div>
<div className='font-semibold'>{event.description}</div>
<div className='flex flex-row gap-4 align-center'>
<p>{event.date}</p>
<p>{start.toLocaleTimeString('en-US', {timeStyle: 'short'})} - {end.toLocaleTimeString('en-US', {timeStyle: 'short'})}</p>
</div>
<div className="mt-1 text-sm relative">
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 inline-block mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 2C8.13401 2 5 5.13401 5 9C5 14.25 12 22 12 22C12 22 19 14.25 19 9C19 5.13401 15.866 2 12 2ZM12 11C10.3431 11 9 9.65685 9 8C9 6.34315 10.3431 5 12 5C13.6569 5 15 6.34315 15 8C15 9.65685 13.6569 11 12 11Z" />
</svg>
{event.location}
</div>
<div className="flex flex-row justify-between align-center">
<Link to={`/events/${event.eventId}`} className="text-blue p-2 rounded-md inline-block">
View Event Details
</Link>
{user && user.isadmin && <button onClick={() => {
setEditEvent(true); setModal(true); setCurrEvent(event);
}} className='hover:bg-blue absolute right-0 bottom-0 mr-6 mb-6 text-md text-blue px-1 bg-white'>Edit</button>}
{
user && user.isadmin && <button onClick={() => {
setEditEvent(true); setModal(true); setCurrEvent(event);
}} className='text-blue text-md p-2'>Edit</button>
}
</div>
</div>
);
Expand Down Expand Up @@ -182,8 +185,9 @@ export default function Events({eventService}) {
<EventModal editEvent={editEvent} handleSubmit={handleSubmit} closeModal={closeModal} currEvent={currEvent}/>
)}
<div className={`${modal && 'blur-sm'} w-full mx-auto flex flex-col justify-center pb-16`}>
<div className='static'>
{!modal && user && user.isadmin && <button className='bg-white hover:bg-blue shadow-sm absolute right-0 text-black w-max m-2 p-2 rounded-lg'

<div className={`flex flex-row ${user && user.isadmin ? 'justify-around' : 'justify-center'}`}>
{!modal && user && user.isadmin && <button className='bg-greywhite hover:bg-blue shadow-sm absolute right-0 text-black w-max m-2 p-2 rounded-lg'
onClick={() => {
setEditEvent(false); setModal(true);
}}>Add Event</button>}
Expand Down
Loading

0 comments on commit db0775e

Please sign in to comment.