import React from 'react'; import MarketingLayout from '@/layouts/mainWebsite'; import { useTranslation } from 'react-i18next'; import { Gift } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { fetchGiftVoucherTiers, createGiftVoucherCheckout, fetchGiftVoucherByCode, type GiftVoucherTier, type GiftVoucherLookupResponse, } from '@/lib/giftVouchers'; import { useLocalizedRoutes } from '@/hooks/useLocalizedRoutes'; import { cn } from '@/lib/utils'; import { useRateLimitHelper } from '@/hooks/useRateLimitHelper'; function useGiftVoucherTiers(initial: GiftVoucherTier[] = []) { const [tiers, setTiers] = React.useState(initial); const [loading, setLoading] = React.useState(initial.length === 0); const [error, setError] = React.useState(null); const { locale } = useLocalizedRoutes(); React.useEffect(() => { if (initial.length > 0) { setLoading(false); return; } fetchGiftVoucherTiers() .then((data) => { const preferredCurrency = locale === 'en' ? 'USD' : 'EUR'; const preferred = data.filter((tier) => tier.currency === preferredCurrency && tier.can_checkout); setTiers(preferred.length > 0 ? preferred : data); }) .catch((err) => setError(err?.message || 'Failed to load tiers')) .finally(() => setLoading(false)); }, [initial, locale]); return { tiers, loading, error }; } function GiftVoucherPage({ tiers: initialTiers = [] }: { tiers: GiftVoucherTier[] }) { const { t } = useTranslation('marketing'); const { locale } = useLocalizedRoutes(); const { tiers, loading, error } = useGiftVoucherTiers(initialTiers); const [submitting, setSubmitting] = React.useState(false); const [serverError, setServerError] = React.useState(null); const [form, setForm] = React.useState({ tier_key: initialTiers.find((t) => t.can_checkout)?.key ?? '', purchaser_email: '', recipient_email: '', recipient_name: '', message: '', accept_terms: false, }); const [errors, setErrors] = React.useState>({}); const [lookupCode, setLookupCode] = React.useState(''); const [lookupResult, setLookupResult] = React.useState(null); const [lookupError, setLookupError] = React.useState(null); const [lookupLoading, setLookupLoading] = React.useState(false); const rateLimit = useRateLimitHelper('voucher'); const selectedTierKey = form.tier_key; const updateField = (key: keyof typeof form, value: string | boolean) => { setForm((prev) => ({ ...prev, [key]: value })); }; const validate = (): boolean => { const nextErrors: Record = {}; if (!form.tier_key) { nextErrors.tier_key = t('gift.error_select_tier'); } if (!form.purchaser_email || !form.purchaser_email.includes('@')) { nextErrors.purchaser_email = t('gift.error_purchaser_email', 'Please enter a valid email.'); } if (form.recipient_email && !form.recipient_email.includes('@')) { nextErrors.recipient_email = t('gift.error_recipient_email', 'Please enter a valid email.'); } if (!form.accept_terms) { nextErrors.accept_terms = t('gift.accept_terms_required'); } setErrors(nextErrors); return Object.keys(nextErrors).length === 0; }; const onSubmit = async () => { if (!validate()) { return; } setSubmitting(true); setServerError(null); try { const successUrl = window.location.origin + `/${locale}/success?type=gift`; const returnUrl = window.location.origin + `/${locale}/gift-card`; const response = await createGiftVoucherCheckout({ tier_key: form.tier_key, purchaser_email: form.purchaser_email, recipient_email: form.recipient_email || undefined, recipient_name: form.recipient_name || undefined, message: form.message || undefined, success_url: successUrl, return_url: returnUrl, }); if (response.id) { sessionStorage.setItem('gift_checkout_id', response.id); } if (response.checkout_url) { window.location.assign(response.checkout_url); } else { setServerError(t('gift.error_checkout')); } } catch (err: any) { setServerError(err?.message || t('gift.error_checkout')); } finally { setSubmitting(false); } }; const onLookup = async () => { if (rateLimit.isLimited(lookupCode)) { setLookupError(t('gift.too_many_attempts')); return; } setLookupLoading(true); setLookupError(null); setLookupResult(null); try { const result = await fetchGiftVoucherByCode(lookupCode); if (result) { setLookupResult(result); rateLimit.clear(lookupCode); } else { setLookupError(t('gift.lookup_not_found')); rateLimit.bump(lookupCode); } } catch (error: any) { setLookupError(error?.message || t('gift.lookup_not_found')); rateLimit.bump(lookupCode); } finally { setLookupLoading(false); } }; return (
{t('gift.badge')}

{t('gift.headline')}

{t('gift.subline')}

{t('gift.validity')}

{error &&
{error}
}
{loading ? (
{Array.from({ length: 4 }).map((_, idx) => (
))}
) : (
{tiers.map((tier) => ( tier.can_checkout && updateField('tier_key', tier.key)} > {tier.label} {tier.amount.toLocaleString()} {tier.currency} {t('gift.card_subline')}

{t('gift.card_body')}

{!tier.can_checkout &&

{t('gift.not_available')}

}
))}
)} {errors.tier_key &&

{errors.tier_key}

}

{t('gift.withdrawal.title')}

{t('gift.withdrawal.body')}

{t('gift.form_title')} {t('gift.form_subtitle')}
updateField('purchaser_email', e.target.value)} /> {errors.purchaser_email &&

{errors.purchaser_email}

}
updateField('recipient_name', e.target.value)} />
updateField('recipient_email', e.target.value)} /> {errors.recipient_email &&

{errors.recipient_email}

}