From 497f0f791ae9d0b332cb02bcb7fd876163e5f070 Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Thu, 26 Mar 2026 22:41:51 +0100 Subject: [PATCH] fix: hide mollie spinners, add placeholders, errors only on submit, sliding interval toggle --- components/checkout/PaymentForm.tsx | 44 ++++++++++++++--------------- components/checkout/PlanSummary.tsx | 44 ++++++++++++++--------------- 2 files changed, 43 insertions(+), 45 deletions(-) diff --git a/components/checkout/PaymentForm.tsx b/components/checkout/PaymentForm.tsx index 9b0ae0d..b3d5b5f 100644 --- a/components/checkout/PaymentForm.tsx +++ b/components/checkout/PaymentForm.tsx @@ -17,8 +17,8 @@ interface PaymentFormProps { const inputClass = 'w-full rounded-lg border border-neutral-700 bg-neutral-800/50 px-3 py-2.5 text-sm text-white placeholder:text-neutral-500 focus:outline-none focus:ring-1 focus:ring-brand-orange focus:border-brand-orange transition-colors' -const mollieFieldClass = - 'w-full rounded-lg border border-neutral-700 bg-neutral-800/50 px-3 py-2.5 h-[42px] transition-colors focus-within:ring-1 focus-within:ring-brand-orange focus-within:border-brand-orange' +const mollieFieldBase = + 'w-full rounded-lg border border-neutral-700 bg-neutral-800/50 px-3 py-2.5 h-[42px] transition-all focus-within:ring-1 focus-within:ring-brand-orange focus-within:border-brand-orange' export default function PaymentForm({ plan, interval, limit }: PaymentFormProps) { const router = useRouter() @@ -31,7 +31,7 @@ export default function PaymentForm({ plan, interval, limit }: PaymentFormProps) const [mollieError, setMollieError] = useState(false) const [formError, setFormError] = useState(null) const [cardErrors, setCardErrors] = useState>({}) - const [touchedFields, setTouchedFields] = useState>(new Set()) + const [submitted, setSubmitted] = useState(false) const [submitting, setSubmitting] = useState(false) const componentsRef = useRef>({ @@ -56,26 +56,25 @@ export default function PaymentForm({ plan, interval, limit }: PaymentFormProps) } try { - const fields: Array<{ type: string; selector: string }> = [ - { type: 'cardHolder', selector: '#mollie-card-holder' }, - { type: 'cardNumber', selector: '#mollie-card-number' }, - { type: 'expiryDate', selector: '#mollie-card-expiry' }, - { type: 'verificationCode', selector: '#mollie-card-cvc' }, + const fields: Array<{ type: string; selector: string; placeholder?: string }> = [ + { type: 'cardHolder', selector: '#mollie-card-holder', placeholder: 'John Doe' }, + { type: 'cardNumber', selector: '#mollie-card-number', placeholder: '1234 5678 9012 3456' }, + { type: 'expiryDate', selector: '#mollie-card-expiry', placeholder: 'MM / YY' }, + { type: 'verificationCode', selector: '#mollie-card-cvc', placeholder: 'CVC' }, ] - for (const { type, selector } of fields) { + for (const { type, selector, placeholder } of fields) { const el = document.querySelector(selector) as HTMLElement | null if (!el) { setMollieError(true) return } - const component = mollie.createComponent(type, { styles: MOLLIE_FIELD_STYLES }) + const opts: Record = { styles: MOLLIE_FIELD_STYLES } + if (placeholder) opts.placeholder = placeholder + const component = mollie.createComponent(type, opts) component.mount(el) component.addEventListener('change', (event: unknown) => { - const e = event as { error?: string; touched?: boolean } - if (e.touched) { - setTouchedFields((prev) => new Set(prev).add(type)) - } + const e = event as { error?: string } setCardErrors((prev) => { const next = { ...prev } if (e.error) next[type] = e.error @@ -104,6 +103,7 @@ export default function PaymentForm({ plan, interval, limit }: PaymentFormProps) }, []) const handleSubmit = async (e: React.FormEvent) => { + setSubmitted(true) e.preventDefault() setFormError(null) if (!country) { @@ -162,8 +162,8 @@ export default function PaymentForm({ plan, interval, limit }: PaymentFormProps) {/* Cardholder name */}
-
- {touchedFields.has('cardHolder') && cardErrors.cardHolder && ( +
+ {submitted && cardErrors.cardHolder && (

{cardErrors.cardHolder}

)}
@@ -171,8 +171,8 @@ export default function PaymentForm({ plan, interval, limit }: PaymentFormProps) {/* Card number */}
-
- {touchedFields.has('cardNumber') && cardErrors.cardNumber && ( +
+ {submitted && cardErrors.cardNumber && (

{cardErrors.cardNumber}

)}
@@ -181,15 +181,15 @@ export default function PaymentForm({ plan, interval, limit }: PaymentFormProps)
-
- {touchedFields.has('expiryDate') && cardErrors.expiryDate && ( +
+ {submitted && cardErrors.expiryDate && (

{cardErrors.expiryDate}

)}
-
- {touchedFields.has('verificationCode') && cardErrors.verificationCode && ( +
+ {submitted && cardErrors.verificationCode && (

{cardErrors.verificationCode}

)}
diff --git a/components/checkout/PlanSummary.tsx b/components/checkout/PlanSummary.tsx index 5982492..f9af880 100644 --- a/components/checkout/PlanSummary.tsx +++ b/components/checkout/PlanSummary.tsx @@ -2,6 +2,7 @@ import { useState } from 'react' import { useRouter, useSearchParams } from 'next/navigation' +import { motion } from 'framer-motion' import { Check } from '@phosphor-icons/react' import { TRAFFIC_TIERS, @@ -83,29 +84,26 @@ export default function PlanSummary({ plan, interval, limit }: PlanSummaryProps)
{/* Interval toggle */} -
- - +
+ {(['month', 'year'] as const).map((iv) => ( + + ))}
{/* Divider */}