diff --git a/components/checkout/PlanSummary.tsx b/components/checkout/PlanSummary.tsx index bec4c3e..a28541b 100644 --- a/components/checkout/PlanSummary.tsx +++ b/components/checkout/PlanSummary.tsx @@ -1,28 +1,36 @@ 'use client' -import { useState } from 'react' +import { useState, useEffect, useCallback } from 'react' import { useRouter, useSearchParams } from 'next/navigation' import { motion } from 'framer-motion' -import { - TRAFFIC_TIERS, - PLAN_PRICES, -} from '@/lib/plans' +import { Select } from '@ciphera-net/ui' +import { TRAFFIC_TIERS, PLAN_PRICES } from '@/lib/plans' +import { COUNTRY_OPTIONS } from '@/lib/countries' +import { calculateVAT, type VATResult } from '@/lib/api/billing' interface PlanSummaryProps { plan: string interval: string limit: number + country: string + vatId: string + onCountryChange: (country: string) => void + onVatIdChange: (vatId: string) => void } -export default function PlanSummary({ plan, interval, limit }: PlanSummaryProps) { +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' + +export default function PlanSummary({ plan, interval, limit, country, vatId, onCountryChange, onVatIdChange }: PlanSummaryProps) { const router = useRouter() const searchParams = useSearchParams() const [currentInterval, setCurrentInterval] = useState(interval) + const [vatResult, setVatResult] = useState(null) + const [vatLoading, setVatLoading] = useState(false) const monthlyCents = PLAN_PRICES[plan]?.[limit] || 0 const isYearly = currentInterval === 'year' - const displayPrice = isYearly ? (monthlyCents * 11) / 100 : monthlyCents / 100 - const monthlyEquivalent = isYearly ? displayPrice / 12 : displayPrice + const baseDisplay = isYearly ? (monthlyCents * 11) / 100 : monthlyCents / 100 const tierLabel = TRAFFIC_TIERS.find((t) => t.value === limit)?.label || @@ -35,18 +43,35 @@ export default function PlanSummary({ plan, interval, limit }: PlanSummaryProps) router.replace(`/checkout?${params.toString()}`, { scroll: false }) } + const fetchVAT = useCallback(async (c: string, v: string, iv: string) => { + if (!c) { setVatResult(null); return } + setVatLoading(true) + try { + const result = await calculateVAT({ plan_id: plan, interval: iv, limit, country: c, vat_id: v || undefined }) + setVatResult(result) + } catch { + setVatResult(null) + } finally { + setVatLoading(false) + } + }, [plan, limit]) + + useEffect(() => { + if (!country) { setVatResult(null); return } + const timer = setTimeout(() => fetchVAT(country, vatId, currentInterval), vatId ? 400 : 0) + return () => clearTimeout(timer) + }, [country, vatId, currentInterval, fetchVAT]) + return ( -
+
+ {/* Plan name + interval toggle */}
- {/* Plan name + badge */}

{plan}

30-day trial
- - {/* Interval toggle */}
{(['month', 'year'] as const).map((iv) => (
- {/* Price row */} -
- - €{isYearly ? monthlyEquivalent.toFixed(2) : displayPrice.toFixed(0)} - - /mo - · {tierLabel} pageviews - {isYearly && ( - - Save 1 month - - )} + {/* Country */} +
+ + onVatIdChange(e.target.value)} + placeholder="e.g. BE0123456789" + className={inputClass} + /> +
+ + {/* Price breakdown */} +
+ {!country ? ( +
+ + €{isYearly ? (baseDisplay / 12).toFixed(2) : baseDisplay.toFixed(0)} + + /mo + excl. VAT · {tierLabel} pageviews + {isYearly && ( + + Save 1 month + + )} +
+ ) : vatLoading ? ( +
+
+ Calculating VAT... +
+ ) : vatResult ? ( +
+
+ Subtotal ({tierLabel} pageviews) + €{vatResult.base_amount} +
+ {vatResult.vat_exempt ? ( +
+ {vatResult.vat_reason} + €0.00 +
+ ) : ( +
+ VAT {vatResult.vat_rate}% + €{vatResult.vat_amount} +
+ )} +
+ Total /mo + €{vatResult.total_amount} +
+ {isYearly && ( +

Billed as €{(parseFloat(vatResult.total_amount) * 12).toFixed(2)}/year

+ )} +
+ ) : null}
- {isYearly && ( -

- €{displayPrice.toFixed(2)} billed yearly -

- )}
) }