2026-07-11 21:21:29 +03:30
"use client" ;
import { zodResolver } from "@hookform/resolvers/zod" ;
import { LoaderIcon , Search } from "lucide-react" ;
import { useMemo , useState } from "react" ;
import { Controller , useForm } from "react-hook-form" ;
import { z } from "zod" ;
import {
Accordion ,
AccordionContent ,
AccordionItem ,
AccordionTrigger ,
} from "@/components/ui/accordion" ;
import { Button } from "@/components/ui/button" ;
import {
Field ,
FieldError ,
FieldGroup ,
FieldLabel ,
} from "@/components/ui/field" ;
import { Input } from "@/components/ui/input" ;
import { Textarea } from "@/components/ui/textarea" ;
import { cn } from "@/lib/utils" ;
const contactFormSchema = z . object ({
email : z
. string ()
. min ( 1 , "ایمیل الزامی است" )
. email ( "لطفاً یک ایمیل معتبر وارد کنید" ),
subject : z.string (). min ( 1 , "موضوع الزامی است" ),
message : z.string (). min ( 1 , "پیام الزامی است" ),
});
type ContactFormData = z . infer < typeof contactFormSchema >;
interface FAQ {
question : string ;
answer : string ;
category? : string ;
}
interface Help3Props {
title? : string ;
description? : string ;
faqs? : FAQ [];
formTitle? : string ;
formDescription? : string ;
className? : string ;
onSubmit ?: ( data : ContactFormData ) => Promise < void >;
}
const Help3 = ({
title = "راهنمای کاربران" ,
description = "در پایگاه دانش جستجو کنید یا درخواست خود را در پایین ثبت کنید." ,
faqs = [
{
question : "چطور رمز عبورم را بازنشانی کنم؟" ,
answer :
"روی لینک «فراموشی رمز عبور» در صفحه ورود کلیک کنید. ایمیل خود را وارد کنید تا لینک بازنشانی برایتان ارسال شود. این لینک پس از ۲۴ ساعت منقضی میشود." ,
category : "حساب کاربری" ,
},
{
question : "چطور پلن خود را ارتقا بدهم؟" ,
answer :
"به تنظیمات > صورتحساب > تغییر پلن بروید. پلن جدید را انتخاب و تأیید کنید. مابهالتفاوت بهصورت تناسبی بلافاصله از کارت شما کسر میشود." ,
category : "صورتحساب" ,
},
{
question : "آیا میتوانم دادههایم را خروجی بگیرم؟" ,
answer :
"بله، به تنظیمات > دادهها > خروجی بروید. میتوانید همه دادهها را در قالب CSV یا JSON دریافت کنید. خروجیهای حجیم ممکن است چند دقیقه زمان ببرند." ,
category : "حساب کاربری" ,
},
{
question : "چه روشهای پرداختی را قبول میکنید؟" ,
answer :
2026-07-21 19:25:31 +03:30
"کارتهای اعتباری اصلی (Visa، Mastercard، American Express)، PayPal و برای پلنهای سالانه بالای ۱٬۰۰۰ ریال، انتقال بانکی را میپذیریم." ,
2026-07-11 21:21:29 +03:30
category : "صورتحساب" ,
},
{
question : "چطور اشتراکم را لغو کنم؟" ,
answer :
"به تنظیمات > صورتحساب > لغو اشتراک بروید. دسترسی شما تا پایان دوره فعلی صورتحساب ادامه دارد و هر زمان میتوانید دوباره فعال کنید." ,
category : "صورتحساب" ,
},
{
question : "آیا دادههای من امن است؟" ,
answer :
"بله، از رمزنگاری استاندارد صنعتی (AES-256) برای دادههای ذخیرهشده و TLS 1.3 برای دادههای در حال انتقال استفاده میکنیم. گواهی SOC 2 Type II داریم." ,
category : "امنیت" ,
},
],
formTitle = "پاسخ خود را پیدا نکردید؟" ,
formDescription = "درخواست خود را ثبت کنید؛ تیم ما ظرف ۲۴ ساعت پاسخ میدهد." ,
className ,
onSubmit ,
} : Help3Props ) => {
const [ searchQuery , setSearchQuery ] = useState ( "" );
const [ isSubmitted , setIsSubmitted ] = useState ( false );
const [ showSuccess , setShowSuccess ] = useState ( false );
const filteredFaqs = useMemo (() => {
if ( ! searchQuery . trim ()) return faqs ;
const query = searchQuery . toLowerCase ();
return faqs . filter (
( faq ) =>
faq . question . toLowerCase (). includes ( query ) ||
faq . answer . toLowerCase (). includes ( query ),
);
}, [ faqs , searchQuery ]);
const form = useForm < ContactFormData >({
resolver : zodResolver ( contactFormSchema ),
mode : "onSubmit" ,
reValidateMode : "onSubmit" ,
defaultValues : {
email : "" ,
subject : "" ,
message : "" ,
},
});
const handleFormSubmit = async ( data : ContactFormData ) => {
try {
if ( onSubmit ) {
await onSubmit ( data );
} else {
console . log ( "Form submitted:" , data );
await new Promise (( resolve ) => setTimeout ( resolve , 1000 ));
}
setIsSubmitted ( true );
setShowSuccess ( true );
form . reset ();
setTimeout (() => setShowSuccess ( false ), 4500 );
setTimeout (() => setIsSubmitted ( false ), 5000 );
} catch {
form . setError ( "root" , {
message : "مشکلی پیش آمد. لطفاً دوباره تلاش کنید." ,
});
}
};
return (
< section className = { cn ( "py-32" , className )}>
< div className = "container" >
< div className = "mx-auto max-w-3xl" >
< div className = "mb-10 text-center" >
< h1 className = "mb-4 text-xl font-medium tracking-tight md:text-2xll" >
{ title }
</ h1 >
< p className = "text-muted-foreground" >{ description }</ p >
</ div >
< div className = "relative mb-8" >
< Search className = "absolute top-1/2 start-3 size-5 -translate-y-1/2 text-muted-foreground" />
< Input
type = "search"
placeholder = "جستجو در پاسخها..."
value = { searchQuery }
onChange = {( e ) => setSearchQuery ( e . target . value )}
className = "ps-10"
/>
</ div >
< Accordion type = "single" collapsible className = "mb-16" >
{ filteredFaqs . length > 0 ? (
filteredFaqs . map (( faq , index ) => (
< AccordionItem key = { index } value = { `item- ${ index } ` }>
< AccordionTrigger className = "text-start" >
< div className = "flex items-center gap-3" >
{ faq . category && (
< span className = "rounded-full bg-muted px-2.5 py-0.5 text-xs font-medium text-muted-foreground" >
{ faq . category }
</ span >
)}
< span >{ faq . question }</ span >
</ div >
</ AccordionTrigger >
< AccordionContent className = "text-muted-foreground" >
{ faq . answer }
</ AccordionContent >
</ AccordionItem >
))
) : (
< p className = "py-8 text-center text-muted-foreground" >
نتیجهای برای « { searchQuery } » یافت نشد .
</ p >
)}
</ Accordion >
< div className = "rounded-xl bg-muted/50 p-8" >
< div className = "mb-6 text-center" >
< h2 className = "mb-2 text-xl font-semibold" >{ formTitle }</ h2 >
< p className = "text-sm text-muted-foreground" >{ formDescription }</ p >
</ div >
{ isSubmitted && (
< div
className = { cn (
"mb-6 rounded-lg border border-green-500/20 bg-green-500/10 p-4 text-center transition-opacity duration-500" ,
showSuccess ? "opacity-100" : "opacity-0" ,
)}
>
< p className = "text-sm font-medium text-green-600 dark:text-green-400" >
درخواست شما ثبت شد . بهزودی با شما تماس میگیریم !
</ p >
</ div >
)}
< form onSubmit = { form . handleSubmit ( handleFormSubmit )}>
< FieldGroup >
< div className = "grid gap-4 sm:grid-cols-2" >
< Controller
control = { form . control }
name = "email"
render = {({ field , fieldState }) => (
< Field data-invalid = { fieldState . invalid }>
< FieldLabel htmlFor = { field . name }>
ایمیل < span className = "text-destructive" > * </ span >
</ FieldLabel >
< Input
{ ...field }
id = { field . name }
type = "email"
aria-invalid = { fieldState . invalid }
placeholder = "you@example.com"
className = "bg-background"
/>
{ fieldState . invalid && (
< FieldError errors = {[ fieldState . error ]} />
)}
</ Field >
)}
/>
< Controller
control = { form . control }
name = "subject"
render = {({ field , fieldState }) => (
< Field data-invalid = { fieldState . invalid }>
< FieldLabel htmlFor = { field . name }>
موضوع < span className = "text-destructive" > * </ span >
</ FieldLabel >
< Input
{ ...field }
id = { field . name }
aria-invalid = { fieldState . invalid }
placeholder = "خلاصه موضوع"
className = "bg-background"
/>
{ fieldState . invalid && (
< FieldError errors = {[ fieldState . error ]} />
)}
</ Field >
)}
/>
</ div >
< Controller
control = { form . control }
name = "message"
render = {({ field , fieldState }) => (
< Field data-invalid = { fieldState . invalid }>
< FieldLabel htmlFor = { field . name }>
پیام < span className = "text-destructive" > * </ span >
</ FieldLabel >
< Textarea
{ ...field }
id = { field . name }
aria-invalid = { fieldState . invalid }
placeholder = "مشکل یا پرسش خود را با جزئیات بنویسید..."
rows = { 5 }
className = "bg-background"
/>
{ fieldState . invalid && (
< FieldError errors = {[ fieldState . error ]} />
)}
</ Field >
)}
/>
{ form . formState . errors . root && (
< p className = "text-sm text-destructive" >
{ form . formState . errors . root . message }
</ p >
)}
< Button
size = "lg"
className = "w-full"
disabled = { form . formState . isSubmitting }
>
{ form . formState . isSubmitting ? (
<>
< LoaderIcon className = "me-2 size-4 animate-spin" />
در حال ارسال ...
</>
) : (
"ثبت درخواست"
)}
</ Button >
</ FieldGroup >
</ form >
</ div >
</ div >
</ div >
</ section >
);
};
export { Help3 };