Files

228 lines
7.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import React, { useState } from 'react'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import { Textarea } from '@/components/ui/textarea'
import { submitDemoRequest } from '@/app/demo/actions'
import type { DemoRequestFormData } from '@/app/demo/actions'
const PRODUCT_OPTIONS = [
{ value: 'آبشده همکار', label: 'آبشده همکار' },
{ value: 'آبشده خانگی', label: 'آبشده خانگی' },
{ value: 'فروشگاه‌ساز طلا', label: 'فروشگاه‌ساز طلا' },
{ value: 'قیمت‌دهی طلا', label: 'قیمت‌دهی طلا' },
{ value: 'سایر', label: 'سایر' },
]
const schema = z.object({
name: z.string().min(2, { message: 'نام و نام خانوادگی حداقل ۲ کاراکتر باشد.' }),
phone: z
.string()
.min(10, { message: 'شماره تماس معتبر وارد کنید.' })
.regex(/^[\d\s۰-۹]+$/, { message: 'فقط اعداد وارد کنید.' }),
product: z
.string()
.refine((v) => v && v !== '__empty__', { message: 'نرم‌افزار مورد نظر را انتخاب کنید.' }),
email: z.string().email({ message: 'ایمیل معتبر وارد کنید.' }).optional().or(z.literal('')),
message: z.string().max(1000).optional(),
})
type FormValues = z.infer<typeof schema>
export function DemoRequestForm() {
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle')
const [errorMessage, setErrorMessage] = useState<string | null>(null)
const {
register,
handleSubmit,
formState: { errors },
setValue,
watch,
reset,
} = useForm<FormValues>({
resolver: zodResolver(schema),
defaultValues: {
name: '',
phone: '',
product: '',
email: '',
message: '',
},
})
const productValue = watch('product')
const onSubmit = async (data: FormValues) => {
setStatus('loading')
setErrorMessage(null)
const product = data.product?.trim() && data.product !== '__empty__' ? data.product : ''
const payload: DemoRequestFormData = {
name: data.name.trim(),
phone: data.phone.replace(/\s/g, ''),
product,
email: data.email?.trim() || undefined,
message: data.message?.trim() || undefined,
}
const result = await submitDemoRequest(payload)
if (result.success) {
setStatus('success')
reset()
} else {
setStatus('error')
setErrorMessage(result.error ?? 'خطایی رخ داد.')
}
}
if (status === 'success') {
return (
<div
className="rounded-xl border border-primary/20 bg-primary/5 p-8 text-center"
role="alert"
>
<h3 className="text-heading-3 font-semibold text-foreground">
درخواست دمو شما ثبت شد
</h3>
<p className="mt-2 text-body text-muted-foreground">
کارشناسان مستر دکور در اسرع وقت با شما تماس می‌گیرند تا زمان جلسه دمو و نمایش امکانات سامانه را هماهنگ کنند.
</p>
</div>
)
}
return (
<form
onSubmit={handleSubmit(onSubmit)}
className="mx-auto max-w-xl space-y-6 rounded-xl border bg-card p-6 shadow-sm md:p-8"
noValidate
>
<div className="grid gap-2 md:grid-cols-2">
<div className="space-y-2">
<Label htmlFor="demo-name" className="text-body-sm font-medium">
نام و نام خانوادگی <span className="text-destructive">*</span>
</Label>
<Input
id="demo-name"
type="text"
placeholder="مثال: علی محمدی"
className="w-full"
autoComplete="name"
aria-invalid={!!errors.name}
{...register('name')}
/>
{errors.name && (
<p className="text-caption text-destructive">{errors.name.message}</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="demo-phone" className="text-body-sm font-medium">
شماره تماس <span className="text-destructive">*</span>
</Label>
<Input
id="demo-phone"
type="tel"
placeholder="۰۹۱۲۳۴۵۶۷۸۹"
className="w-full"
autoComplete="tel"
aria-invalid={!!errors.phone}
{...register('phone')}
/>
{errors.phone && (
<p className="text-caption text-destructive">{errors.phone.message}</p>
)}
</div>
</div>
<div className="space-y-2">
<Label className="text-body-sm font-medium">
نرم‌افزار مورد نظر <span className="text-destructive">*</span>
</Label>
<Select
value={productValue || '__empty__'}
onValueChange={(v) => setValue('product', v === '__empty__' ? '' : v)}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="انتخاب نرم‌افزار" />
</SelectTrigger>
<SelectContent>
<SelectItem value="__empty__">انتخاب نرم‌افزار</SelectItem>
{PRODUCT_OPTIONS.map((opt) => (
<SelectItem key={opt.value} value={opt.value}>
{opt.label}
</SelectItem>
))}
</SelectContent>
</Select>
{errors.product && (
<p className="text-caption text-destructive">{errors.product.message}</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="demo-email" className="text-body-sm font-medium">
ایمیل (اختیاری)
</Label>
<Input
id="demo-email"
type="email"
placeholder="نمونه@example.com"
className="w-full"
autoComplete="email"
aria-invalid={!!errors.email}
{...register('email')}
/>
{errors.email && (
<p className="text-caption text-destructive">{errors.email.message}</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="demo-message" className="text-body-sm font-medium">
توضیحات (اختیاری)
</Label>
<Textarea
id="demo-message"
placeholder="در صورت نیاز توضیح دهید؛ مثلاً تعداد شعبه، نوع استفاده یا سوال خاص."
rows={4}
className="resize-none"
aria-invalid={!!errors.message}
{...register('message')}
/>
{errors.message && (
<p className="text-caption text-destructive">{errors.message.message}</p>
)}
</div>
{status === 'error' && errorMessage && (
<p className="rounded-md bg-destructive/10 p-3 text-body-sm text-destructive">
{errorMessage}
</p>
)}
<Button
type="submit"
size="lg"
variant="primary"
className="w-full"
disabled={status === 'loading'}
>
{status === 'loading' ? 'در حال ارسال...' : 'ثبت درخواست دمو'}
</Button>
</form>
)
}