From 635ce5d9937bc323366c05be0766ebc8207833bf Mon Sep 17 00:00:00 2001 From: euxia Date: Thu, 3 Sep 2026 17:25:54 +0800 Subject: [PATCH 1/5] feat(pycon): add category and description metadata to registration steps --- .../pages/client/pycon/register/steps/RegistrationSteps.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/client/pycon/register/steps/RegistrationSteps.ts b/frontend/src/pages/client/pycon/register/steps/RegistrationSteps.ts index a0f755e2..438ffc31 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 = { From 6d0a55c5340e91e382e715705d9f773d3d8a38a4 Mon Sep 17 00:00:00 2001 From: euxia Date: Thu, 3 Sep 2026 17:27:15 +0800 Subject: [PATCH 2/5] feat(pycon): add category and description metadata to registration steps --- .../pages/client/pycon/register/Register.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/client/pycon/register/Register.tsx b/frontend/src/pages/client/pycon/register/Register.tsx index f81882c0..e9ba8b92 100644 --- a/frontend/src/pages/client/pycon/register/Register.tsx +++ b/frontend/src/pages/client/pycon/register/Register.tsx @@ -97,7 +97,23 @@ 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 && ( From a9c42862359ef56afb3222198cbdb15d26f4f6fe Mon Sep 17 00:00:00 2001 From: euxia Date: Thu, 3 Sep 2026 17:27:36 +0800 Subject: [PATCH 3/5] feat(pycon): add responsive step header with category and description --- .../src/pages/client/pycon/register/Register.tsx | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/frontend/src/pages/client/pycon/register/Register.tsx b/frontend/src/pages/client/pycon/register/Register.tsx index e9ba8b92..57a51e84 100644 --- a/frontend/src/pages/client/pycon/register/Register.tsx +++ b/frontend/src/pages/client/pycon/register/Register.tsx @@ -99,19 +99,9 @@ const Register: FC = () => { {currentStep.id !== 'EventDetails' && currentStep.id !== 'Success' && (
- {currentStep.category && ( -

- {currentStep.category} -

- )} -

- {currentStep.title} -

- {currentStep.description && ( -

- {currentStep.description} -

- )} + {currentStep.category &&

{currentStep.category}

} +

{currentStep.title}

+ {currentStep.description &&

{currentStep.description}

}
)} From 27dc5bdc5c0b8dd7bb85aa380f280a472a4262d4 Mon Sep 17 00:00:00 2001 From: euxia Date: Thu, 3 Sep 2026 17:27:47 +0800 Subject: [PATCH 4/5] feat(pycon): create reusable SummaryCard and SummaryRow components --- .../pycon/register/steps/SummaryCard.tsx | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 frontend/src/pages/client/pycon/register/steps/SummaryCard.tsx 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 00000000..6b67c61f --- /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} +
+ ); +}; From f2deb8b0233de6ed07034231c0e4e36aa0935dbc Mon Sep 17 00:00:00 2001 From: euxia Date: Thu, 3 Sep 2026 17:27:56 +0800 Subject: [PATCH 5/5] feat(pycon): redesign summary step with structured summary cards and consent section --- .../pycon/register/steps/SummaryStep.tsx | 305 +++++++----------- 1 file changed, 118 insertions(+), 187 deletions(-) diff --git a/frontend/src/pages/client/pycon/register/steps/SummaryStep.tsx b/frontend/src/pages/client/pycon/register/steps/SummaryStep.tsx index f98bc108..8133057a 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 }) => ( +
+
+ + +
+
- -
- )} - + )} + +
);