'use client' import { useEffect, useRef, useState } from 'react' import { useRouter, useSearchParams } from 'next/navigation' import Script from 'next/script' import { Lock, ShieldCheck } from '@phosphor-icons/react' import { Select } from '@ciphera-net/ui' import { COUNTRY_OPTIONS } from '@/lib/countries' import { initMollie, getMollie, MOLLIE_FIELD_STYLES, type MollieComponent } from '@/lib/mollie' import { createEmbeddedCheckout } from '@/lib/api/billing' interface PaymentFormProps { plan: string interval: string limit: number } 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' export default function PaymentForm({ plan, interval, limit }: PaymentFormProps) { const router = useRouter() const searchParams = useSearchParams() const currentInterval = searchParams.get('interval') || interval const [country, setCountry] = useState('') const [vatId, setVatId] = useState('') const [mollieReady, setMollieReady] = useState(false) const [mollieError, setMollieError] = useState(false) const [formError, setFormError] = useState(null) const [cardErrors, setCardErrors] = useState>({}) const [touchedFields, setTouchedFields] = useState>(new Set()) const [submitting, setSubmitting] = useState(false) const componentsRef = useRef>({ cardHolder: null, cardNumber: null, expiryDate: null, verificationCode: null, }) const [scriptLoaded, setScriptLoaded] = useState(false) // Mount Mollie components AFTER both script loaded AND DOM elements exist useEffect(() => { if (!scriptLoaded) return // Small delay to ensure DOM elements are painted const timer = setTimeout(() => { const mollie = initMollie() if (!mollie) { setMollieError(true) return } 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' }, ] for (const { type, selector } of fields) { const el = document.querySelector(selector) as HTMLElement | null if (!el) { setMollieError(true) return } const component = mollie.createComponent(type, { styles: MOLLIE_FIELD_STYLES }) 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)) } setCardErrors((prev) => { const next = { ...prev } if (e.error) next[type] = e.error else delete next[type] return next }) }) componentsRef.current[type] = component } setMollieReady(true) } catch (err) { console.error('Mollie mount error:', err) setMollieError(true) } }, 100) return () => clearTimeout(timer) }, [scriptLoaded]) // Cleanup Mollie components on unmount useEffect(() => { return () => { Object.values(componentsRef.current).forEach((c) => c?.unmount()) } }, []) const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setFormError(null) if (!country) { setFormError('Please select your country') return } const mollie = getMollie() if (!mollie) { setFormError('Payment system not loaded. Please refresh.') return } setSubmitting(true) try { const { token, error } = await mollie.createToken() if (error || !token) { setFormError(error?.message || 'Invalid card details.') setSubmitting(false) return } const result = await createEmbeddedCheckout({ plan_id: plan, interval: currentInterval, limit, country, vat_id: vatId || undefined, card_token: token, }) if (result.status === 'success') router.push('/checkout?status=success') else if (result.status === 'pending' && result.redirect_url) window.location.href = result.redirect_url } catch (err) { setFormError((err as Error)?.message || 'Payment failed. Please try again.') } finally { setSubmitting(false) } } return ( <>