diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 184f8bb1..39519518 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,6 +12,7 @@ "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-radio-group": "^1.2.0", + "@radix-ui/react-select": "^2.1.1", "@radix-ui/react-slot": "^1.1.0", "calendar-link": "^2.7.0", "class-variance-authority": "^0.7.0", @@ -24,13 +25,14 @@ "react": "^18", "react-dom": "^18", "react-faq-component": "^1.3.4", - "react-hook-form": "^7.52.2", + "react-hook-form": "^7.53.0", "react-icons": "^5.2.1", "sanitize-html": "^2.13.0", "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7", "vaul": "^0.9.1", - "yup": "^1.4.0" + "yup": "^1.4.0", + "zod": "^3.23.8" }, "devDependencies": { "@types/node": "^20", @@ -134,6 +136,44 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", + "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", + "license": "MIT" + }, "node_modules/@hookform/resolvers": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.0.tgz", @@ -449,11 +489,40 @@ "node": ">=14" } }, + "node_modules/@radix-ui/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", + "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==", + "license": "MIT" + }, "node_modules/@radix-ui/primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", + "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collection": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", @@ -659,6 +728,38 @@ } } }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", + "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-portal": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz", @@ -788,6 +889,49 @@ } } }, + "node_modules/@radix-ui/react-select": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz", + "integrity": "sha512-8iRDfyLtzxlprOo9IicnzvpsO1wNCkuwzzCM+Z5Rb5tNOpCdMvcc2AkzX0Fz+Tz9v6NJ5B/7EEgyZveo4FBRfQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", @@ -881,6 +1025,24 @@ } } }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-size": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", @@ -898,6 +1060,35 @@ } } }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz", + "integrity": "sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", + "license": "MIT" + }, "node_modules/@rushstack/eslint-patch": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.3.tgz", @@ -4683,9 +4874,9 @@ } }, "node_modules/react-hook-form": { - "version": "7.52.2", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.2.tgz", - "integrity": "sha512-pqfPEbERnxxiNMPd0bzmt1tuaPcVccywFDpyk2uV5xCIBphHV5T8SVnX9/o3kplPE1zzKt77+YIoq+EMwJp56A==", + "version": "7.53.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.0.tgz", + "integrity": "sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==", "engines": { "node": ">=18.0.0" }, @@ -5960,6 +6151,14 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/frontend/package.json b/frontend/package.json index 49aecb04..b8198b51 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,6 +13,7 @@ "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-radio-group": "^1.2.0", + "@radix-ui/react-select": "^2.1.1", "@radix-ui/react-slot": "^1.1.0", "calendar-link": "^2.7.0", "class-variance-authority": "^0.7.0", @@ -25,13 +26,14 @@ "react": "^18", "react-dom": "^18", "react-faq-component": "^1.3.4", - "react-hook-form": "^7.52.2", + "react-hook-form": "^7.53.0", "react-icons": "^5.2.1", "sanitize-html": "^2.13.0", "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7", "vaul": "^0.9.1", - "yup": "^1.4.0" + "yup": "^1.4.0", + "zod": "^3.23.8" }, "devDependencies": { "@types/node": "^20", diff --git a/frontend/src/components/Form/form.tsx b/frontend/src/components/Form/form.tsx new file mode 100644 index 00000000..50a7d630 --- /dev/null +++ b/frontend/src/components/Form/form.tsx @@ -0,0 +1,178 @@ +'use client' + +import * as React from 'react' +import * as LabelPrimitive from '@radix-ui/react-label' +import { Slot } from '@radix-ui/react-slot' +import { + Controller, + ControllerProps, + FieldPath, + FieldValues, + FormProvider, + useFormContext, +} from 'react-hook-form' + +import { cn } from '@/lib/utils' +import { Label } from '../Label' + +const Form = FormProvider + +type FormFieldContextValue< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath, +> = { + name: TName +} + +const FormFieldContext = React.createContext( + {} as FormFieldContextValue, +) + +const FormField = < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath, +>({ + ...props +}: ControllerProps) => { + return ( + + + + ) +} + +const useFormField = () => { + const fieldContext = React.useContext(FormFieldContext) + const itemContext = React.useContext(FormItemContext) + const { getFieldState, formState } = useFormContext() + + const fieldState = getFieldState(fieldContext.name, formState) + + if (!fieldContext) { + throw new Error('useFormField should be used within ') + } + + const { id } = itemContext + + return { + id, + name: fieldContext.name, + formItemId: `${id}-form-item`, + formDescriptionId: `${id}-form-item-description`, + formMessageId: `${id}-form-item-message`, + ...fieldState, + } +} + +type FormItemContextValue = { + id: string +} + +const FormItemContext = React.createContext( + {} as FormItemContextValue, +) + +const FormItem = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => { + const id = React.useId() + + return ( + +
+ + ) +}) +FormItem.displayName = 'FormItem' + +const FormLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + const { error, formItemId } = useFormField() + + return ( +

{name}

- Starts {dayjs(start_date).format('DD MMMM, YYYY')} at {dayjs(start_date).format('hh:mm A')} + + Starts {dayjs(start_date).format('DD MMMM, YYYY')} at{' '} + {dayjs(start_date).format('hh:mm A')} + {city && City: {city}} - +
Hey Everyone
+ className='prose' + dangerouslySetInnerHTML={{ __html: sanitizedDescription }} + />

When

@@ -97,23 +100,27 @@ const EventContainer = async ({
- {venue &&
-

- - Where -

-

{venue}

-
} + {venue && ( +
+

+ + Where +

+

{venue}

+
+ )}
- {venue_map_link && } + {venue_map_link && ( + + )}
@@ -123,12 +130,16 @@ const EventContainer = async ({
RSVP for this event now!
- Registration ends {dayjs(registration_end_date).format('DD MMMM, YYYY')} at {dayjs(registration_end_date).format('hh:mm A')} + + Registration ends{' '} + {dayjs(registration_end_date).format('DD MMMM, YYYY')} at{' '} + {dayjs(registration_end_date).format('hh:mm A')} + {event_mode} - + ) diff --git a/frontend/src/containers/RegisterEvent/RegisterEvent.config.ts b/frontend/src/containers/RegisterEvent/RegisterEvent.config.ts new file mode 100644 index 00000000..41e09fc3 --- /dev/null +++ b/frontend/src/containers/RegisterEvent/RegisterEvent.config.ts @@ -0,0 +1,83 @@ +import { FieldType } from './RegisterEvent.types' + +export const REGISTER_FORM_FIELDS: (FieldType | Array)[] = [ + [ + { + name: 'first_name', + label: 'First Name', + placeholder: 'Enter your First Name', + type: 'text', + }, + { + name: 'last_name', + label: 'Last Name', + placeholder: 'Enter your Last Name', + type: 'text', + }, + ], + { + name: 'email', + label: 'Email', + placeholder: 'Email', + type: 'text', + }, + [ + { + name: 'professional_status', + label: 'Professional Status', + placeholder: 'Select Professional Status', + type: 'select', + options: [ + { label: 'Working Professional', value: 'working_professional' }, + { label: 'Student', value: 'student' }, + { label: 'Freelancer', value: 'freelancer' }, + { label: 'Other', value: 'other' }, + ], + }, + { + name: 'organization', + label: 'Organization', + placeholder: 'Enter your organization', + type: 'text', + }, + ], + { + name: 'description', + label: 'About You', + placeholder: 'Eg. CEO of Google', + type: 'text', + }, + [ + { + name: 'gender', + label: 'Gender', + placeholder: 'Select gender', + type: 'select', + options: [ + { label: 'Male', value: 'male' }, + { label: 'Female', value: 'female' }, + { label: 'Other', value: 'other' }, + ], + }, + { + name: 'linkedin', + label: 'LinkedIn URL', + placeholder: 'Your linkedIn profile', + type: 'text', + }, + ], + [ + { + name: 'github', + label: 'Github URL', + placeholder: 'Your github profile', + type: 'text', + }, + { + name: 'twitter', + label: 'Twitter URL', + placeholder: 'Your twitter profile', + type: 'text', + }, + ], +] diff --git a/frontend/src/containers/RegisterEvent/RegisterEvent.tsx b/frontend/src/containers/RegisterEvent/RegisterEvent.tsx index 3b2ee85e..5e0f2b80 100644 --- a/frontend/src/containers/RegisterEvent/RegisterEvent.tsx +++ b/frontend/src/containers/RegisterEvent/RegisterEvent.tsx @@ -1,4 +1,8 @@ -import React from 'react' +'use client' + +import React, { useState } from 'react' +import { yupResolver } from '@hookform/resolvers/yup' + import { Drawer, DrawerClose, @@ -10,16 +14,73 @@ import { DrawerTrigger, Button, Input, - Label, - RadioGroup, - RadioGroupItem, + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectItem, + FormField, + FormItem, + FormLabel, + FormControl, + FormMessage, + Form, } from '@components' +import { SubmitHandler, useForm } from 'react-hook-form' +import { RegisterEventForm } from './RegisterEvent.types' +import { API_ENDPOINTS, REGISTER_EVENT_FORM_SCHEMA } from '@constants' +import { REGISTER_FORM_FIELDS } from './RegisterEvent.config' +import { fetchData } from '@/utils' +import { enqueueSnackbar } from 'notistack' + +export const RegisterEvent = ({ eventId }: { eventId: string }) => { + const [isOpen, setIsOpen] = useState(false) + + const { + register, + control, + reset, + formState: { errors, ...restFormState }, + handleSubmit, + ...rest + } = useForm({ + resolver: yupResolver(REGISTER_EVENT_FORM_SCHEMA), + defaultValues: { + first_name: '', + last_name: '', + email: '', + linkedin: '', + organization: '', + description: '', + }, + }) + + const onSubmit: SubmitHandler = async (data) => { + const res = await fetchData<{ message: string }>( + API_ENDPOINTS.registerEvent.replace(':id', eventId), + { + method: 'POST', + body: JSON.stringify({ + event: eventId, + ...data, + }), + }, + ) + if (res.statusCode === 200 || res.statusCode === 201) { + enqueueSnackbar(res?.data?.message, { variant: 'success' }) + } else { + enqueueSnackbar(res?.error?.message, { + variant: 'error', + }) + } + reset() + setIsOpen(false) + } -export const RegisterEvent = () => { return ( - + - @@ -32,98 +93,134 @@ export const RegisterEvent = () => { Please fill the information carefully -
-
-
- - -
-
- - -
-
-
- - -
-
-
- -
- - -
-
- - + + + {REGISTER_FORM_FIELDS.map((item, i) => + Array.isArray(item) ? ( +
+ {item.map(({ name, label, placeholder, type, options }) => ( +
+ ( + + {label} + {type === 'select' ? ( + + ) : ( + + + + )} + + {errors[name]?.message ?? ' '} + + + )} + /> +
+ ))}
-
- - + ) : ( +
+ ( + + {item.label} + {item.type === 'select' ? ( + + ) : ( + + + + )} + + {errors[item.name]?.message ?? ' '} + + + )} + />
- -
-
- - -
-
-
- - -
-
- - -
-
-
- - -
-
- - -
-
- - - - - - - + ), + )} + + + + + + + + ) diff --git a/frontend/src/containers/RegisterEvent/RegisterEvent.types.ts b/frontend/src/containers/RegisterEvent/RegisterEvent.types.ts new file mode 100644 index 00000000..1c8f8001 --- /dev/null +++ b/frontend/src/containers/RegisterEvent/RegisterEvent.types.ts @@ -0,0 +1,32 @@ +export type RegisterEventForm = { + email: string + first_name: string + last_name: string + professional_status: + | 'working_professional' + | 'student' + | 'freelancer' + | 'other' + gender: 'male' | 'female' | 'other' + organization?: string + description?: string + linkedin: string + github?: string + twitter?: string +} + +type SelectField = { + type: 'select' + options: { label: string; value: string }[] +} + +type InputField = { + type: 'text' + options?: never +} + +export type FieldType = { + label: string + placeholder: string + name: keyof RegisterEventForm +} & (SelectField | InputField) diff --git a/frontend/src/sections/EventSection/EventCard.tsx b/frontend/src/sections/EventSection/EventCard.tsx index 58a67078..a812ff7e 100644 --- a/frontend/src/sections/EventSection/EventCard.tsx +++ b/frontend/src/sections/EventSection/EventCard.tsx @@ -6,7 +6,6 @@ import dayjs from 'dayjs' import event2 from '../../../public/02.svg' import { useRouter } from 'next/navigation' - interface EventProps { eventId: string title: string @@ -24,7 +23,7 @@ const EventCard: React.FC = ({ imageSrc, venue, time, - event_mode + event_mode, }) => { const router = useRouter() @@ -66,12 +65,14 @@ const EventCard: React.FC = ({ Mode: {event_mode}

- {venue &&

- Venue: -
- {venue} -

} -

{dayjs(time).format('hh:mm A')}

+ {venue && ( +

+ Venue: +
+ {venue} +

+ )} + {/*

{dayjs(time).format('hh:mm A')}

*/}