gift voucher language fixes + move into user menu
This commit is contained in:
103
resources/js/pages/marketing/GiftVoucherStatus.tsx
Normal file
103
resources/js/pages/marketing/GiftVoucherStatus.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
import React from 'react';
|
||||
import MarketingLayout from '@/layouts/mainWebsite';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { fetchGiftVoucherByCode, type GiftVoucherLookupResponse } from '@/lib/giftVouchers';
|
||||
import { useRateLimitHelper } from '@/hooks/useRateLimitHelper';
|
||||
|
||||
const GiftVoucherStatus: React.FC = () => {
|
||||
const { t, i18n } = useTranslation('marketing');
|
||||
const [code, setCode] = React.useState('');
|
||||
const [result, setResult] = React.useState<GiftVoucherLookupResponse | null>(null);
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
const rateLimit = useRateLimitHelper('voucher');
|
||||
|
||||
const onLookup = async () => {
|
||||
if (rateLimit.isLimited(code)) {
|
||||
setError(t('gift.too_many_attempts'));
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
setResult(null);
|
||||
try {
|
||||
const data = await fetchGiftVoucherByCode(code);
|
||||
if (data) {
|
||||
setResult(data);
|
||||
rateLimit.clear(code);
|
||||
} else {
|
||||
setError(t('gift.lookup_not_found'));
|
||||
rateLimit.bump(code);
|
||||
}
|
||||
} catch (e: any) {
|
||||
setError(e?.message || t('gift.lookup_not_found'));
|
||||
rateLimit.bump(code);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<MarketingLayout title={t('gift.lookup_title')}>
|
||||
<section className="bg-gradient-to-b from-background via-muted/30 to-background py-16">
|
||||
<div className="mx-auto flex max-w-3xl flex-col gap-8 px-4 sm:px-6">
|
||||
<div className="space-y-3 text-center">
|
||||
<h1 className="text-3xl font-bold text-foreground">{t('gift.lookup_title')}</h1>
|
||||
<p className="text-muted-foreground">{t('gift.lookup_subtitle')}</p>
|
||||
</div>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t('gift.lookup_label')}</CardTitle>
|
||||
<CardDescription>{t('gift.lookup_subtitle')}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="code">{t('gift.lookup_label')}</Label>
|
||||
<Input
|
||||
id="code"
|
||||
placeholder="GIFT-XXXXXX"
|
||||
value={code}
|
||||
onChange={(e) => setCode(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Button onClick={onLookup} disabled={loading || !code.trim()}>
|
||||
{loading ? t('gift.processing', 'Checking...') : t('gift.lookup_cta')}
|
||||
</Button>
|
||||
{error && <p className="text-sm text-destructive">{error}</p>}
|
||||
{result && (
|
||||
<div className="space-y-2 rounded-md border bg-muted/30 p-4 text-sm">
|
||||
<p className="font-semibold">{t('gift.lookup_result_code', { code: result.code })}</p>
|
||||
<p className="text-muted-foreground">
|
||||
{t('gift.lookup_result_value', {
|
||||
amount: result.amount.toFixed(2),
|
||||
currency: result.currency,
|
||||
})}
|
||||
</p>
|
||||
{result.expires_at && (
|
||||
<p className="text-muted-foreground">
|
||||
{t('gift.lookup_result_expires', {
|
||||
date: new Date(result.expires_at).toLocaleDateString(i18n.language),
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
<p className="text-muted-foreground">
|
||||
{t(`gift.lookup_status.${result.status}`, result.status)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
</MarketingLayout>
|
||||
);
|
||||
};
|
||||
|
||||
GiftVoucherStatus.layout = (page: React.ReactNode) => page;
|
||||
|
||||
export default GiftVoucherStatus;
|
||||
Reference in New Issue
Block a user