From dfd1a2cc472a38997912b91fd4d3d92ac3522ef7 Mon Sep 17 00:00:00 2001 From: Sean Date: Sun, 31 Mar 2024 00:10:08 -0700 Subject: [PATCH] show submitted feedback on event page, improve standalone eventdetails spacing, feedback form submit btn --- src/components/events/EventDetail/index.tsx | 8 ++-- .../events/EventDetail/style.module.scss | 13 +++++++ .../events/EventDetail/style.module.scss.d.ts | 1 + src/components/events/FeedbackForm/index.tsx | 10 +++-- .../events/FeedbackForm/style.module.scss | 5 ++- src/lib/hoc/withAccessType.ts | 20 ++++++++-- src/pages/events/[uuid].tsx | 37 ++++++++++++++----- src/styles/pages/event.module.scss | 7 ++-- src/styles/pages/event.module.scss.d.ts | 1 + 9 files changed, 78 insertions(+), 24 deletions(-) diff --git a/src/components/events/EventDetail/index.tsx b/src/components/events/EventDetail/index.tsx index a3dff68c..ed15474a 100644 --- a/src/components/events/EventDetail/index.tsx +++ b/src/components/events/EventDetail/index.tsx @@ -42,16 +42,16 @@ const EventDetail = ({ event, attended, inModal = false }: EventDetailProps) => } return ( -
+
{inModal ? ( ) : null} -
+
Event Cover Image
-
+
{description} diff --git a/src/components/events/EventDetail/style.module.scss b/src/components/events/EventDetail/style.module.scss index 5b0b9b2c..9d8ae791 100644 --- a/src/components/events/EventDetail/style.module.scss +++ b/src/components/events/EventDetail/style.module.scss @@ -11,6 +11,11 @@ position: relative; width: 80vw; + &.standalone { + padding: 0; + width: auto; + } + .image { aspect-ratio: 1920 / 1080; border-radius: 10px; @@ -36,10 +41,18 @@ .description { padding: 0 2.5rem; width: 100%; + + &.standalone { + padding: 0; + } } .image { border-radius: 10px 10px 0 0; + + &.standalone { + border-radius: 10px; + } } } diff --git a/src/components/events/EventDetail/style.module.scss.d.ts b/src/components/events/EventDetail/style.module.scss.d.ts index c84f5211..a7953af3 100644 --- a/src/components/events/EventDetail/style.module.scss.d.ts +++ b/src/components/events/EventDetail/style.module.scss.d.ts @@ -10,6 +10,7 @@ export type Styles = { feedbackBtn: string; header: string; image: string; + standalone: string; }; export type ClassNames = keyof Styles; diff --git a/src/components/events/FeedbackForm/index.tsx b/src/components/events/FeedbackForm/index.tsx index b083ff60..4bfd726b 100644 --- a/src/components/events/FeedbackForm/index.tsx +++ b/src/components/events/FeedbackForm/index.tsx @@ -1,7 +1,7 @@ import { Typography } from '@/components/common'; import { showToast } from '@/lib'; import { FeedbackAPI } from '@/lib/api'; -import { PublicEvent } from '@/lib/types/apiResponses'; +import { PublicEvent, PublicFeedback } from '@/lib/types/apiResponses'; import { Community, FeedbackType } from '@/lib/types/enums'; import { reportError, toCommunity } from '@/lib/utils'; import { useState } from 'react'; @@ -18,9 +18,10 @@ export const communityToFeedbackType: Record = { interface FeedbackFormProps { authToken: string; event: PublicEvent; + onSubmit?: (feedback: PublicFeedback) => void; } -const FeedbackForm = ({ authToken, event }: FeedbackFormProps) => { +const FeedbackForm = ({ authToken, event, onSubmit }: FeedbackFormProps) => { const [source, setSource] = useState(''); const [description, setDescription] = useState(''); @@ -30,16 +31,17 @@ const FeedbackForm = ({ authToken, event }: FeedbackFormProps) => { onSubmit={async e => { e.preventDefault(); try { - await FeedbackAPI.addFeedback(authToken, { + const feedback = await FeedbackAPI.addFeedback(authToken, { event: event.uuid, source: source, - description: description.padEnd(20, ' '), + description, type: communityToFeedbackType[toCommunity(event.committee)], }); showToast( 'Feedback received!', 'Thank you for taking the time to help us make our events better for you.' ); + onSubmit?.(feedback); } catch (error) { reportError('Failed to submit feedback', error); } diff --git a/src/components/events/FeedbackForm/style.module.scss b/src/components/events/FeedbackForm/style.module.scss index 6eb62333..748bc76b 100644 --- a/src/components/events/FeedbackForm/style.module.scss +++ b/src/components/events/FeedbackForm/style.module.scss @@ -22,7 +22,7 @@ } .submit { - align-self: center; + align-self: flex-start; background-color: var(--theme-text-on-background-1); border-radius: 2rem; color: var(--theme-background); @@ -30,5 +30,8 @@ font-weight: bold; min-height: 3rem; padding: 0 2rem; + @media (max-width: vars.$breakpoint-sm) { + align-self: center; + } } } diff --git a/src/lib/hoc/withAccessType.ts b/src/lib/hoc/withAccessType.ts index 818a45b8..1cee57c4 100644 --- a/src/lib/hoc/withAccessType.ts +++ b/src/lib/hoc/withAccessType.ts @@ -4,7 +4,21 @@ import { CookieService } from '@/lib/services'; import type { URL } from '@/lib/types'; import { PrivateProfile } from '@/lib/types/apiResponses'; import { CookieType, UserAccessType } from '@/lib/types/enums'; -import type { GetServerSideProps, GetServerSidePropsContext } from 'next'; +import type { + GetServerSideProps, + GetServerSidePropsContext, + GetServerSidePropsResult, + PreviewData, +} from 'next'; +import { ParsedUrlQuery } from 'querystring'; + +export type GetServerSidePropsWithUser< + Props extends { [key: string]: any } = { [key: string]: any }, + Params extends ParsedUrlQuery = ParsedUrlQuery, + Preview extends PreviewData = PreviewData +> = ( + context: GetServerSidePropsContext & { user: PrivateProfile } +) => Promise>; interface AccessTypeOptions { /** @@ -21,7 +35,7 @@ interface AccessTypeOptions { * @returns */ export default function withAccessType( - gssp: GetServerSideProps, + gssp: GetServerSidePropsWithUser, validAccessTypes: UserAccessType[], { redirectTo = config.loginRoute }: AccessTypeOptions = {} ): GetServerSideProps { @@ -84,7 +98,7 @@ export default function withAccessType( if (!validAccessTypes.includes(userAccessLevel)) return missingAccessRedirect; // If we haven't short-circuited, user has valid access. Show the page and add the user prop. - const originalReturnValue = await gssp(context); + const originalReturnValue = await gssp({ ...context, user }); // Insert the user object to the original return value if it doesn't exist already if ('props' in originalReturnValue) { const existingProps = await Promise.resolve(originalReturnValue.props); diff --git a/src/pages/events/[uuid].tsx b/src/pages/events/[uuid].tsx index 0cedf456..da730268 100644 --- a/src/pages/events/[uuid].tsx +++ b/src/pages/events/[uuid].tsx @@ -1,40 +1,58 @@ +import { Typography } from '@/components/common'; import EventDetail from '@/components/events/EventDetail'; +import Feedback from '@/components/events/Feedback'; import FeedbackForm from '@/components/events/FeedbackForm'; -import { EventAPI, UserAPI } from '@/lib/api'; -import withAccessType from '@/lib/hoc/withAccessType'; +import { EventAPI, FeedbackAPI, UserAPI } from '@/lib/api'; +import withAccessType, { GetServerSidePropsWithUser } from '@/lib/hoc/withAccessType'; import { CookieService, PermissionService } from '@/lib/services'; -import type { PublicEvent } from '@/lib/types/apiResponses'; +import type { PublicEvent, PublicFeedback } from '@/lib/types/apiResponses'; import { CookieType } from '@/lib/types/enums'; import styles from '@/styles/pages/event.module.scss'; -import type { GetServerSideProps } from 'next'; -import { useMemo } from 'react'; +import { useMemo, useState } from 'react'; interface EventPageProps { token: string; event: PublicEvent; attended: boolean; + feedback: PublicFeedback | null; } -const EventPage = ({ token, event, attended }: EventPageProps) => { +const EventPage = ({ token, event, attended, feedback: initFeedback }: EventPageProps) => { const started = useMemo(() => new Date() >= new Date(event.start), [event.start]); + const [feedback, setFeedback] = useState(initFeedback); + + let feedbackForm = null; + if (feedback) { + feedbackForm = ( +
+ + Your Feedback + + +
+ ); + } else if (started) { + feedbackForm = ; + } return (
- {started ? : null} + {feedbackForm}
); }; export default EventPage; -const getServerSidePropsFunc: GetServerSideProps = async ({ params, req, res }) => { +const getServerSidePropsFunc: GetServerSidePropsWithUser = async ({ params, req, res, user }) => { const uuid = params?.uuid as string; const token = CookieService.getServerCookie(CookieType.ACCESS_TOKEN, { req, res }); try { - const [event, attendances] = await Promise.all([ + const [event, attendances, [feedback = null]] = await Promise.all([ EventAPI.getEvent(uuid, token), UserAPI.getAttendancesForCurrentUser(token), + FeedbackAPI.getFeedback(token, { user: user.uuid, event: uuid }), ]); return { props: { @@ -42,6 +60,7 @@ const getServerSidePropsFunc: GetServerSideProps = async ({ params, req, res }) token, event, attended: attendances.some(attendance => attendance.event.uuid === uuid), + feedback, }, }; } catch { diff --git a/src/styles/pages/event.module.scss b/src/styles/pages/event.module.scss index 0af24bcf..5dc0f135 100644 --- a/src/styles/pages/event.module.scss +++ b/src/styles/pages/event.module.scss @@ -5,8 +5,9 @@ margin: 0 auto; max-width: 70rem; - div:first-child { - padding: 0; - width: auto; + .submittedFeedback { + display: flex; + flex-direction: column; + gap: 1rem; } } diff --git a/src/styles/pages/event.module.scss.d.ts b/src/styles/pages/event.module.scss.d.ts index 190f135c..03f54589 100644 --- a/src/styles/pages/event.module.scss.d.ts +++ b/src/styles/pages/event.module.scss.d.ts @@ -1,5 +1,6 @@ export type Styles = { page: string; + submittedFeedback: string; }; export type ClassNames = keyof Styles;