Moshavereh sazmani
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { z } from 'zod'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||
import { CheckCircle2, Loader2 } from 'lucide-react'
|
||||
|
||||
const consultingAreas = [
|
||||
'اینتگریشن',
|
||||
'هوشمندسازی',
|
||||
'RAG',
|
||||
'Performance',
|
||||
'امنیت',
|
||||
'معماری نرمافزار',
|
||||
'داده و تحلیل',
|
||||
'سایر',
|
||||
] as const
|
||||
|
||||
const formSchema = z.object({
|
||||
fullName: z.string().min(2, 'نام و نام خانوادگی الزامی است'),
|
||||
organization: z.string().min(1, 'نام سازمان الزامی است'),
|
||||
phone: z.string().min(10, 'شماره تماس معتبر وارد کنید'),
|
||||
area: z.string().min(1, 'حوزه مشاوره را انتخاب کنید'),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
|
||||
type FormValues = z.infer<typeof formSchema>
|
||||
|
||||
export function ConsultingForm() {
|
||||
const [submitted, setSubmitted] = useState(false)
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [submitError, setSubmitError] = useState<string | null>(null)
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
fullName: '',
|
||||
organization: '',
|
||||
phone: '',
|
||||
area: '',
|
||||
description: '',
|
||||
},
|
||||
})
|
||||
|
||||
async function onSubmit(data: FormValues) {
|
||||
setSubmitError(null)
|
||||
setIsSubmitting(true)
|
||||
try {
|
||||
const res = await fetch('/api/consulting', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
const json = await res.json().catch(() => ({}))
|
||||
if (!res.ok) {
|
||||
setSubmitError(json.error || 'ارسال درخواست ناموفق بود. لطفاً دوباره تلاش کنید.')
|
||||
return
|
||||
}
|
||||
setSubmitted(true)
|
||||
form.reset()
|
||||
} catch {
|
||||
setSubmitError('خطا در ارتباط با سرور. لطفاً دوباره تلاش کنید.')
|
||||
} finally {
|
||||
setIsSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (submitted) {
|
||||
return (
|
||||
<Alert className="border-primary/50 bg-primary/5 text-center">
|
||||
<CheckCircle2 className="h-5 w-5 text-primary" />
|
||||
<AlertDescription className="text-base font-medium">
|
||||
در سریعترین زمان ممکن با شما تماس میگیریم.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
||||
{submitError && (
|
||||
<Alert variant="destructive">
|
||||
<AlertDescription>{submitError}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="fullName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>نام و نام خانوادگی</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="نام و نام خانوادگی" {...field} className="h-11" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="organization"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>نام سازمان</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="نام سازمان یا شرکت" {...field} className="h-11" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="phone"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>شماره تماس</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="tel" placeholder="۰۹۱۲۳۴۵۶۷۸۹" {...field} className="h-11" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="area"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>در چه حوزهای مشاوره میخواهید؟</FormLabel>
|
||||
<Select onValueChange={field.onChange} value={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger className="h-11 w-full">
|
||||
<SelectValue placeholder="انتخاب حوزه" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{consultingAreas.map((area) => (
|
||||
<SelectItem key={area} value={area}>
|
||||
{area}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="description"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>توضیحات (اختیاری)</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
placeholder="در صورت نیاز توضیح بیشتری بنویسید..."
|
||||
className="min-h-24"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit" size="lg" className="w-full" disabled={isSubmitting}>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<Loader2 className="size-5 animate-spin" aria-hidden />
|
||||
در حال ارسال...
|
||||
</>
|
||||
) : (
|
||||
'ثبت درخواست'
|
||||
)}
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
@@ -10,13 +10,16 @@ export default function ContentSection() {
|
||||
<div className="grid gap-6 sm:grid-cols-2 md:gap-12 lg:gap-24">
|
||||
<div className="relative mb-6 sm:mb-0">
|
||||
<div className="bg-linear-to-b aspect-76/59 relative rounded-2xl from-zinc-300 to-transparent p-px dark:from-zinc-700">
|
||||
<Image
|
||||
src="/assets/Echosystem.png"
|
||||
className="rounded-[15px] object-cover"
|
||||
alt="اکوسیستم یکپارچه فیپ"
|
||||
width={1207}
|
||||
height={929}
|
||||
/>
|
||||
<div className="relative aspect-[1207/929] w-full overflow-hidden rounded-[15px] bg-muted flex items-center justify-center">
|
||||
<Image
|
||||
src="/assets/Echosystem.png"
|
||||
className="rounded-[15px] object-cover"
|
||||
alt="اکوسیستم یکپارچه فیپ"
|
||||
width={1207}
|
||||
height={929}
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ const menuItems = [
|
||||
{ name: 'صفحه اصلی', href: '/' },
|
||||
{ name: 'دانشنامه', href: '/blog' },
|
||||
{ name: 'راه حلها', href: '/solutions' },
|
||||
{ name: 'مشاوره سازمانی', href: '/consulting' },
|
||||
// { name: 'قیمتگذاری', href: '/pricing' },
|
||||
{ name: 'درباره ما', href: '/about' },
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user