diff --git a/frontend/src/components/Input.tsx b/frontend/src/components/Input.tsx index c0202027..7aff8be9 100644 --- a/frontend/src/components/Input.tsx +++ b/frontend/src/components/Input.tsx @@ -11,8 +11,7 @@ const Input = React.forwardRef(({ className, type, type={type} className={cn( 'text-foreground flex h-9 w-full rounded-md border border-border bg-input px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50', - pyconStyles && - 'bg-pycon-dirty-white text-pycon-dark-blue font-inter text-base md:text-lg h-13 md:h-14 px-5 py-3.5 rounded-2xl border-2 border-transparent focus-visible:border-pycon-teal/40 focus-visible:ring-2 focus-visible:ring-pycon-teal/10 placeholder:text-pycon-lavender/60 placeholder:font-normal placeholder:font-inter shadow-xs', + pyconStyles && 'border-none shadow-none bg-pycon-dirty-white placeholder:text-pycon-lavender text-pycon-violet font-nunito', className )} ref={ref} diff --git a/frontend/src/components/RichContent/RichTextContent.test.ts b/frontend/src/components/RichContent/RichTextContent.test.ts index c4ee99ef..6746cf45 100644 --- a/frontend/src/components/RichContent/RichTextContent.test.ts +++ b/frontend/src/components/RichContent/RichTextContent.test.ts @@ -1,11 +1,10 @@ -import type { Content } from '@tiptap/react'; import { describe, expect, it } from 'vitest'; import { sanitizeRichContent, sanitizeRichHtmlContent } from './RichTextContent'; +import type { Content } from '@tiptap/react'; describe('RichTextContent XSS protections', () => { it('sanitizes malicious HTML strings', () => { - const maliciousHtml = - '

Safe text

click'; + const maliciousHtml = '

Safe text

click'; const sanitizedHtml = sanitizeRichHtmlContent(maliciousHtml).toLowerCase(); diff --git a/frontend/src/components/RichContent/RichTextContent.tsx b/frontend/src/components/RichContent/RichTextContent.tsx index 5f192d2b..632c5442 100644 --- a/frontend/src/components/RichContent/RichTextContent.tsx +++ b/frontend/src/components/RichContent/RichTextContent.tsx @@ -1,10 +1,10 @@ +import DOMPurify from 'dompurify'; import { cn } from '@/utils/classes'; import './RichContent.css'; import Placeholder from '@tiptap/extension-placeholder'; import TextAlign from '@tiptap/extension-text-align'; import { Content, EditorContent, useEditor } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; -import DOMPurify from 'dompurify'; interface RichTextContentProps { content: Content; @@ -61,4 +61,4 @@ function RichTextContent({ content, className }: RichTextContentProps) { return ; } -export default RichTextContent; \ No newline at end of file +export default RichTextContent; diff --git a/frontend/src/model/evaluations.ts b/frontend/src/model/evaluations.ts index b9905dcf..b49f9753 100644 --- a/frontend/src/model/evaluations.ts +++ b/frontend/src/model/evaluations.ts @@ -1,12 +1,5 @@ type QuestionType = - | 'text_short' - | 'text_long' - | 'multiple_choice_dropdown' - | 'multiple_choice' - | 'multiple_choice_dropdown' - | 'multiple_answers' - | 'slider' - | 'radio_buttons'; + 'text_short' | 'text_long' | 'multiple_choice_dropdown' | 'multiple_choice' | 'multiple_choice_dropdown' | 'multiple_answers' | 'slider' | 'radio_buttons'; export interface QuestionConfigItem { questionType: QuestionType; diff --git a/frontend/src/model/preregistrations.ts b/frontend/src/model/preregistrations.ts index 5d461468..477b15c1 100644 --- a/frontend/src/model/preregistrations.ts +++ b/frontend/src/model/preregistrations.ts @@ -4,23 +4,22 @@ import { Registration } from './registrations'; export type AcceptanceStatus = 'PENDING' | 'ACCEPTED' | 'REJECTED'; -export interface PreRegistration - extends Omit< - Registration, - | 'certificateClaimed' - | 'amountPaid' - | 'paymentId' - | 'registrationId' - | 'referenceNumber' - | 'gcashPayment' - | 'gcashPaymentUrl' - | 'discountCode' - | 'type' - | 'certificateGenerated' - | 'certificateClaimed' - | 'certificateImgObjectKey' - | 'certificatePdfObjectKey' - > { +export interface PreRegistration extends Omit< + Registration, + | 'certificateClaimed' + | 'amountPaid' + | 'paymentId' + | 'registrationId' + | 'referenceNumber' + | 'gcashPayment' + | 'gcashPaymentUrl' + | 'discountCode' + | 'type' + | 'certificateGenerated' + | 'certificateClaimed' + | 'certificateImgObjectKey' + | 'certificatePdfObjectKey' +> { type: 'preregistration'; acceptanceStatus: AcceptanceStatus; preRegistrationId: string; diff --git a/frontend/src/model/pycon/evaluations.ts b/frontend/src/model/pycon/evaluations.ts index 88437aca..b959de48 100644 --- a/frontend/src/model/pycon/evaluations.ts +++ b/frontend/src/model/pycon/evaluations.ts @@ -1,12 +1,5 @@ type QuestionType = - | 'text_short' - | 'text_long' - | 'multiple_choice_dropdown' - | 'multiple_choice' - | 'multiple_choice_dropdown' - | 'multiple_answers' - | 'slider' - | 'radio_buttons'; + 'text_short' | 'text_long' | 'multiple_choice_dropdown' | 'multiple_choice' | 'multiple_choice_dropdown' | 'multiple_answers' | 'slider' | 'radio_buttons'; export interface QuestionConfigItem { questionType: QuestionType; diff --git a/frontend/src/model/pycon/registrations.ts b/frontend/src/model/pycon/registrations.ts index 07c35bf8..c5393670 100644 --- a/frontend/src/model/pycon/registrations.ts +++ b/frontend/src/model/pycon/registrations.ts @@ -94,7 +94,8 @@ export const mapCreateRegistrationDataForPayment = (registration: RegisterFormVa export const mapCreateRegistrationValues = (registration: RegisterFormValues, eventId: string, email?: string): CreateRegistration => ({ ...mapCreateRegistrationDataForPayment(registration, eventId, email), amountPaid: roundUpToTwoDecimals(registration.total), - transactionId: registration.transactionId || `price-${registration.total}-${registration.discountCode || 'null'}-${crypto.randomUUID().slice(0, 5).toUpperCase()}` + transactionId: + registration.transactionId || `price-${registration.total}-${registration.discountCode || 'null'}-${crypto.randomUUID().slice(0, 5).toUpperCase()}` }); export type UpdateRegistration = Omit; diff --git a/frontend/src/pages/client/pycon/register/Register.tsx b/frontend/src/pages/client/pycon/register/Register.tsx index 5e934f39..e26c84e0 100644 --- a/frontend/src/pages/client/pycon/register/Register.tsx +++ b/frontend/src/pages/client/pycon/register/Register.tsx @@ -90,28 +90,26 @@ const Register: FC = () => { return (
+ {currentStep.id === 'Miscellaneous' &&
Registration
}
- {showStepper && !shouldBeVertical && ( -
- -
+ {currentStep.id !== 'EventDetails' && currentStep.id !== 'Success' && ( + <> +

{currentStep.title}

+ {currentStep.id === 'Miscellaneous' && ( +

A few more things to help us make the event better for you.

+ )} + )} - {currentStep.id !== 'EventDetails' && currentStep.id !== 'Success' &&

{currentStep.title}

} -
{showStepper && shouldBeVertical && (
)} -
{currentStep.id === 'EventDetails' && } {currentStep.id === 'BasicInfo' && } diff --git a/frontend/src/pages/client/pycon/register/steps/MiscellaneousStep.tsx b/frontend/src/pages/client/pycon/register/steps/MiscellaneousStep.tsx index f3e3af5a..7334b2b8 100644 --- a/frontend/src/pages/client/pycon/register/steps/MiscellaneousStep.tsx +++ b/frontend/src/pages/client/pycon/register/steps/MiscellaneousStep.tsx @@ -17,19 +17,44 @@ interface Props { const MiscellaneousStep: FC = () => { return ( - <> -
+
+
+

Community

{({ field }) => ( -
- Are you a member of any local tech community? - field.onChange(Boolean(value))} value={field.value} className="flex flex-wrap gap-4 py-3 mt-auto"> -
- - - - - +
+ + field.onChange(val === 'true')} + value={typeof field.value === 'boolean' ? String(field.value) : undefined} + className="flex flex-wrap gap-4 py-3 mt-auto" + > +
+
+ + +
+
+ + +
@@ -39,15 +64,28 @@ const MiscellaneousStep: FC = () => { {({ field }) => ( -
- Would you like to volunteer in the future? - field.onChange(Boolean(value))} value={field.value} className="flex flex-wrap gap-4 py-3 mt-auto"> -
- - - - - +
+ + field.onChange(val === 'true')} + value={typeof field.value === 'boolean' ? String(field.value) : undefined} + className="flex flex-wrap gap-4 py-3 mt-auto" + > +
+
+ + +
+
+ + +
@@ -56,14 +94,17 @@ const MiscellaneousStep: FC = () => {
-
+
+

+ Preferences (optional) +

{({ field }) => (
- + Dietary Restrictions - +
)} @@ -72,16 +113,16 @@ const MiscellaneousStep: FC = () => { {({ field }) => (
- + Accessibility Needs - +
)}
- +
); }; diff --git a/frontend/src/styles/pycon.css b/frontend/src/styles/pycon.css index 5e787215..c1e84a9f 100644 --- a/frontend/src/styles/pycon.css +++ b/frontend/src/styles/pycon.css @@ -58,4 +58,3 @@ body[data-page='pycon'] { @apply font-sora font-extrabold text-pycon-teal scroll-m-20 text-4xl tracking-tight lg:text-5xl; } } - diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 991c7551..0f3dac78 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,8 +1,8 @@ import path from 'path'; import { defineConfig } from 'vite'; +import { ViteImageOptimizer } from 'vite-plugin-image-optimizer'; // import { VitePWA } from 'vite-plugin-pwa'; import react from '@vitejs/plugin-react'; -import { ViteImageOptimizer } from 'vite-plugin-image-optimizer'; // https://vitejs.dev/config/ export default defineConfig(({ mode }) => { @@ -12,24 +12,23 @@ export default defineConfig(({ mode }) => { ViteImageOptimizer({ svg: { plugins: [ - { - name: 'removeMetadata', - }, - { - name: 'removeViewBox', - }, - - ]}, + { + name: 'removeMetadata' + }, + { + name: 'removeViewBox' + } + ] + }, png: { - quality: 80 + quality: 80 }, jpeg: { - quality: 80 + quality: 80 }, jpg: { - quality: 80 - }, - + quality: 80 + } }) // VitePWA({ // registerType: 'autoUpdate', // Automatically update the service worker