Skip to content

Commit

Permalink
show submitted feedback on event page, improve standalone eventdetail…
Browse files Browse the repository at this point in the history
…s spacing, feedback form submit btn
  • Loading branch information
SheepTester committed Mar 31, 2024
1 parent d4d05eb commit dfd1a2c
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 24 deletions.
8 changes: 4 additions & 4 deletions src/components/events/EventDetail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ const EventDetail = ({ event, attended, inModal = false }: EventDetailProps) =>
}

return (
<div className={styles.container}>
<div className={`${styles.container} ${inModal ? '' : styles.standalone}`}>
{inModal ? (
<button type="submit" aria-label="Close" className={styles.close}>
<CloseIcon aria-hidden className={styles.closeIcon} />
</button>
) : null}
<div className={styles.image}>
<div className={`${styles.image} ${inModal ? '' : styles.standalone}`}>
<Image src={displayCover} alt="Event Cover Image" style={{ objectFit: 'cover' }} fill />
</div>
<div className={styles.header}>
<div className={`${styles.header} ${inModal ? '' : styles.standalone}`}>
<div className={styles.eventDetails}>
<div>
<Typography
Expand All @@ -77,7 +77,7 @@ const EventDetail = ({ event, attended, inModal = false }: EventDetailProps) =>
<Typography
variant="h5/regular"
style={{ wordBreak: 'break-word' }}
className={styles.description}
className={`${styles.description} ${inModal ? '' : styles.standalone}`}
>
{description}
</Typography>
Expand Down
13 changes: 13 additions & 0 deletions src/components/events/EventDetail/style.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
position: relative;
width: 80vw;

&.standalone {
padding: 0;
width: auto;
}

.image {
aspect-ratio: 1920 / 1080;
border-radius: 10px;
Expand All @@ -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;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/components/events/EventDetail/style.module.scss.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type Styles = {
feedbackBtn: string;
header: string;
image: string;
standalone: string;
};

export type ClassNames = keyof Styles;
Expand Down
10 changes: 6 additions & 4 deletions src/components/events/FeedbackForm/index.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -18,9 +18,10 @@ export const communityToFeedbackType: Record<Community, FeedbackType> = {
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('');

Expand All @@ -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);
}
Expand Down
5 changes: 4 additions & 1 deletion src/components/events/FeedbackForm/style.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@
}

.submit {
align-self: center;
align-self: flex-start;
background-color: var(--theme-text-on-background-1);
border-radius: 2rem;
color: var(--theme-background);
font-size: 1rem;
font-weight: bold;
min-height: 3rem;
padding: 0 2rem;
@media (max-width: vars.$breakpoint-sm) {
align-self: center;
}
}
}
20 changes: 17 additions & 3 deletions src/lib/hoc/withAccessType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Params, Preview> & { user: PrivateProfile }
) => Promise<GetServerSidePropsResult<Props>>;

interface AccessTypeOptions {
/**
Expand All @@ -21,7 +35,7 @@ interface AccessTypeOptions {
* @returns
*/
export default function withAccessType(
gssp: GetServerSideProps,
gssp: GetServerSidePropsWithUser,
validAccessTypes: UserAccessType[],
{ redirectTo = config.loginRoute }: AccessTypeOptions = {}
): GetServerSideProps {
Expand Down Expand Up @@ -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);
Expand Down
37 changes: 28 additions & 9 deletions src/pages/events/[uuid].tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,66 @@
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 = (
<div className={styles.submittedFeedback}>
<Typography variant="h2/bold" component="h2">
Your Feedback
</Typography>
<Feedback feedback={feedback} />
</div>
);
} else if (started) {
feedbackForm = <FeedbackForm event={event} authToken={token} onSubmit={setFeedback} />;
}

return (
<div className={styles.page}>
<EventDetail event={event} attended={attended} />
{started ? <FeedbackForm event={event} authToken={token} /> : null}
{feedbackForm}
</div>
);
};

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: {
title: event.title,
token,
event,
attended: attendances.some(attendance => attendance.event.uuid === uuid),
feedback,
},
};
} catch {
Expand Down
7 changes: 4 additions & 3 deletions src/styles/pages/event.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
1 change: 1 addition & 0 deletions src/styles/pages/event.module.scss.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export type Styles = {
page: string;
submittedFeedback: string;
};

export type ClassNames = keyof Styles;
Expand Down

0 comments on commit dfd1a2c

Please sign in to comment.