diff --git a/frontend/src/pages/client/pycon/register/Register.tsx b/frontend/src/pages/client/pycon/register/Register.tsx index 5e934f3..5174fc4 100644 --- a/frontend/src/pages/client/pycon/register/Register.tsx +++ b/frontend/src/pages/client/pycon/register/Register.tsx @@ -103,7 +103,13 @@ const Register: FC = () => { )} - {currentStep.id !== 'EventDetails' && currentStep.id !== 'Success' &&

{currentStep.title}

} + {currentStep.id !== 'EventDetails' && currentStep.id !== 'Success' && ( +
+ {currentStep.category &&

{currentStep.category}

} +

{currentStep.title}

+ {currentStep.description &&

{currentStep.description}

} +
+ )}
{showStepper && shouldBeVertical && ( diff --git a/frontend/src/pages/client/pycon/register/steps/RegistrationSteps.ts b/frontend/src/pages/client/pycon/register/steps/RegistrationSteps.ts index a0f755e..438ffc3 100644 --- a/frontend/src/pages/client/pycon/register/steps/RegistrationSteps.ts +++ b/frontend/src/pages/client/pycon/register/steps/RegistrationSteps.ts @@ -4,6 +4,8 @@ export type RegisterStepId = 'EventDetails' | 'BasicInfo' | 'TicketSelection' | export interface RegisterStep extends Step { id: RegisterStepId; + category?: string; + description?: string; } export const STEP_EVENT_DETAILS: RegisterStep = { @@ -32,7 +34,9 @@ export const STEP_PAYMENT: RegisterStep = { export const STEP_SUMMARY: RegisterStep = { id: 'Summary', - title: 'Summary' + title: 'Confirm Details', + description: 'Review your information before submitting.', + category: 'REGISTRATION' }; export const STEP_SUCCESS: RegisterStep = { diff --git a/frontend/src/pages/client/pycon/register/steps/SummaryCard.tsx b/frontend/src/pages/client/pycon/register/steps/SummaryCard.tsx new file mode 100644 index 0000000..6b67c61 --- /dev/null +++ b/frontend/src/pages/client/pycon/register/steps/SummaryCard.tsx @@ -0,0 +1,42 @@ +import { FC, ReactNode } from 'react'; +import { cn } from '@/utils/classes'; + +interface SummaryCardProps { + title: string; + children?: ReactNode; + className?: string; +} + +export const SummaryCard: FC = ({ title, children, className }) => { + return ( +
+

{title}

+ {/*

+ {title} +

*/} +
{children}
+
+ ); +}; + +interface SummaryRowProps { + label: string; + value: ReactNode; + isAlt?: boolean; + className?: string; +} + +export const SummaryRow: FC = ({ label, value, isAlt = false, className }) => { + return ( +
+ {label} + {value} +
+ ); +}; diff --git a/frontend/src/pages/client/pycon/register/steps/SummaryStep.tsx b/frontend/src/pages/client/pycon/register/steps/SummaryStep.tsx index f98bc10..8133057 100644 --- a/frontend/src/pages/client/pycon/register/steps/SummaryStep.tsx +++ b/frontend/src/pages/client/pycon/register/steps/SummaryStep.tsx @@ -1,23 +1,26 @@ +import React from 'react'; import { useFormContext, useWatch } from 'react-hook-form'; import Checkbox from '@/components/Checkbox'; import { FormItem, FormError } from '@/components/Form'; import Label from '@/components/Label'; -import Separator from '@/components/Separator'; import { Event } from '@/model/events'; import { formatMoney, formatPercentage } from '@/utils/functions'; import { RegisterFormValues } from '../../hooks/useRegisterForm'; +import { SummaryCard, SummaryRow } from './SummaryCard'; const PYCON_CODE_OF_CONDUCT = import.meta.env.VITE_PYCON_CODE_OF_CONDUCT || 'https://pycon-davao.durianpy.org/code-of-conduct'; interface SummaryProps { event: Event; } + const SummaryStep = ({ event }: SummaryProps) => { const { control } = useFormContext(); const [ email, firstName, lastName, + nickname, pronouns, contactNumber, organization, @@ -31,19 +34,18 @@ const SummaryStep = ({ event }: SummaryProps) => { transactionFee, discountedPrice, total, - // availTShirt, - // shirtType, - // shirtSize, communityInvolvement, futureVolunteer, dietaryRestrictions, - accessibilityNeeds + accessibilityNeeds, + validIdObjectKey ] = useWatch({ control, name: [ 'email', 'firstName', 'lastName', + 'nickname', 'pronouns', 'contactNumber', 'organization', @@ -57,200 +59,129 @@ const SummaryStep = ({ event }: SummaryProps) => { 'transactionFee', 'discountedPrice', 'total', - // 'availTShirt', - // 'shirtType', - // 'shirtSize', 'communityInvolvement', 'futureVolunteer', 'dietaryRestrictions', - 'accessibilityNeeds' + 'accessibilityNeeds', + 'validIdObjectKey' ] }); const ticketType = event.ticketTypes?.find((ticket) => ticket.id === ticketTypeId); - const { hasMultipleTicketTypes } = event; - - return ( -
-

Please review the information below before submitting.

- -
-
- First name - - {firstName} - - - Last name - - {lastName} - - - Pronouns - - {pronouns || 'Prefer not to say'} - - - Email - - {email} - - - Phone number - - {contactNumber} - - - Dietary Restrictions - - {dietaryRestrictions || 'None'} - - - Accessibility Needs - - {accessibilityNeeds || 'None'} - - - Facebook Link - - {facebookLink} - - - Linkedin Link - - {linkedInLink || 'None'} - - - Organization - - {organization} - - - Title - - {jobTitle} - - - - - {hasMultipleTicketTypes && ( - <> - Ticket Type - - {ticketType?.name} - - - )} + const fullName = [firstName, lastName].filter(Boolean).join(' ') || '-'; - Will join sprint day? - - {sprintDay ? 'Yes' : 'No'} - + const formatSocials = () => { + const socials: string[] = []; + if (facebookLink) socials.push(`[FB] ${facebookLink}`); + if (linkedInLink) socials.push(`[in] ${linkedInLink}`); + return socials.length > 0 ? socials.join(' ยท ') : 'None'; + }; - {/* Will avail tshirt? - - {availTShirt ? 'Yes' : 'No'} - + const getUploadedIdDisplay = () => { + if (!validIdObjectKey) return 'None'; + const parts = validIdObjectKey.split('/'); + return parts[parts.length - 1] || 'Uploaded'; + }; - {availTShirt && ( - <> - Tshirt Type - - {shirtType} - - - Tshirt Size - - {shirtSize} - - - )} */} - - Are you a member of any local tech community? - - {communityInvolvement ? 'Yes' : 'No'} - - - Would you like to volunteer in the future? - - {futureVolunteer ? 'Yes' : 'No'} - - {event.paidEvent && event.status !== 'preregistration' &&
} - {event.paidEvent && event.status !== 'preregistration' && ( - <> - Price: -

{formatMoney(event.price, 'PHP')}

- - {discountPercentage && validCode && discountedPrice ? ( - <> - Discount Code: - - {validCode} - - - Discount - - {discountPercentage ? {formatPercentage(discountPercentage)} : 'None'} - - - Discounted Price - - {formatMoney(discountedPrice ?? event.price, 'PHP')} - - - ) : ( - <> - )} - - {sprintDay && event.sprintDayPrice && ( - <> - Sprint Day Fee: -

{formatMoney(event.sprintDayPrice, 'PHP')}

- - )} - - Transaction Fee - {transactionFee ? {formatMoney(transactionFee, 'PHP')} : 'None'} - - Total - {formatMoney(total ?? event.price, 'PHP')} - - )} -
-
- -
- - {({ field }) => ( -
-
- - + return ( +
+ {/* 1. Basic Information Card */} + + + + + + + + + + + + {/* 2. Ticket Selection Card */} + + + + + {event.paidEvent && event.status !== 'preregistration' && ( + <> + + + {discountPercentage && validCode && discountedPrice ? ( + <> + + + + + ) : null} + + {sprintDay && event.sprintDayPrice ? : null} + + + {formatMoney(total ?? event.price, 'PHP')}} + isAlt={true} + /> + + )} + + + {/* 3. Miscellaneous Card */} + + + + + + + + {/* 4. Promotions & Verification Card */} + + + + + + + {/* 5. Consent Section */} +
+

CONSENT

+ +
+ + {({ field }) => ( +
+
+ + +
+
- -
- )} - - - - {({ field }) => ( -
-
- - + )} + + + + {({ field }) => ( +
+
+ + +
+
- -
- )} - + )} + +
);