canina/frontend/application/components/ContactFormClient.tsx
parsa aghaei 8d1b786a24
All checks were successful
Deploy Canina / deploy (push) Successful in 1m50s
chore(brand): rename all Persian occurrences of کانینا to کنینا across the project
2026-08-16 16:40:08 +03:30

255 lines
10 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 { useEffect, useState } from "react";
import { Mail, Phone, MapPin, Send, CheckCircle2 } from "lucide-react";
import api from "../lib/services/api";
interface ContactInfoItem {
key: string;
title: string;
value: string;
icon?: string;
}
export default function ContactFormClient() {
const [infoItems, setInfoItems] = useState<ContactInfoItem[]>([]);
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [subject, setSubject] = useState("");
const [message, setMessage] = useState("");
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
const [error, setError] = useState("");
useEffect(() => {
async function fetchContactInfo() {
try {
const res = await api.get("/contact/info");
setInfoItems(res.data || []);
} catch (err) {
console.error("Failed to fetch contact info", err);
}
}
fetchContactInfo();
}, []);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const cleanPhone = phone.trim();
if (!name.trim() || !cleanPhone || !message.trim()) {
setError("لطفاً نام، شماره موبایل و متن پیام را وارد کنید.");
return;
}
if (!/^09\d{9}$/.test(cleanPhone)) {
setError("شماره همراه وارد شده معتبر نیست. (مثال: ۰۹۱۲۳۴۵۶۷۸۹)");
return;
}
setError("");
setLoading(true);
try {
await api.post("/contact", {
name,
phone,
subject,
message,
});
setSuccess(true);
setName("");
setPhone("");
setSubject("");
setMessage("");
} catch (err: unknown) {
const errorObj = err as { response?: { data?: { message?: string } } };
setError(
errorObj.response?.data?.message || "خطایی در ثبت پیام رخ داده است. لطفاً مجدداً تلاش کنید."
);
} finally {
setLoading(false);
}
};
const getIcon = (iconName?: string) => {
switch (iconName) {
case "mail":
return <Mail className="w-6 h-6" />;
case "map-pin":
return <MapPin className="w-6 h-6" />;
case "phone":
default:
return <Phone className="w-6 h-6" />;
}
};
return (
<div className="grid lg:grid-cols-12 gap-12 items-start">
{/* Contact Details */}
<div className="lg:col-span-5 space-y-8">
<h3 className="text-2xl font-black text-medical-gray-900">اطلاعات نمایندگی</h3>
<div className="space-y-6">
{infoItems.length > 0 ? (
infoItems.map((item) => (
<div
key={item.key}
className="flex gap-4 p-6 bg-white border border-medical-gray-200 rounded-[2rem] shadow-sm"
>
<div className="w-12 h-12 bg-canina-blue/5 text-canina-blue rounded-2xl flex items-center justify-center shrink-0">
{getIcon(item.icon)}
</div>
<div>
<h4 className="text-xs font-black text-medical-gray-400 uppercase tracking-wider mb-1">
{item.title}
</h4>
<div className="text-sm font-bold text-medical-gray-900 leading-relaxed whitespace-pre-wrap">
{item.value}
</div>
</div>
</div>
))
) : (
<>
<div className="flex gap-4 p-6 bg-white border border-medical-gray-200 rounded-[2rem] shadow-sm">
<div className="w-12 h-12 bg-canina-blue/5 text-canina-blue rounded-2xl flex items-center justify-center shrink-0">
<Phone className="w-6 h-6" />
</div>
<div>
<h4 className="text-xs font-black text-medical-gray-400 uppercase tracking-wider mb-1">
تلفنهای تماس
</h4>
<p className="text-lg font-black text-medical-gray-900 tracking-wider">
۰۲۱-۸۸۸۸ ۴۴۴۴
</p>
<p className="text-sm text-medical-gray-500 font-bold">
شنبه تا چهارشنبه ۹:۰۰ الی ۱۸:۰۰
</p>
</div>
</div>
<div className="flex gap-4 p-6 bg-white border border-medical-gray-200 rounded-[2rem] shadow-sm">
<div className="w-12 h-12 bg-canina-blue/5 text-canina-blue rounded-2xl flex items-center justify-center shrink-0">
<Mail className="w-6 h-6" />
</div>
<div>
<h4 className="text-xs font-black text-medical-gray-400 uppercase tracking-wider mb-1">
پست الکترونیک
</h4>
<p className="text-sm font-black text-medical-gray-900">info@canina-iran.com</p>
<p className="text-xs text-medical-gray-500 font-bold">
پاسخگویی در کمتر از ۲۴ ساعت کاری
</p>
</div>
</div>
<div className="flex gap-4 p-6 bg-white border border-medical-gray-200 rounded-[2rem] shadow-sm">
<div className="w-12 h-12 bg-canina-blue/5 text-canina-blue rounded-2xl flex items-center justify-center shrink-0">
<MapPin className="w-6 h-6" />
</div>
<div>
<h4 className="text-xs font-black text-medical-gray-400 uppercase tracking-wider mb-1">
نشانی دفتر مرکزی
</h4>
<p className="text-sm font-bold text-medical-gray-900 leading-relaxed">
تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹
</p>
</div>
</div>
</>
)}
</div>
</div>
{/* Contact Form */}
<div className="lg:col-span-7 bg-white border border-medical-gray-200 rounded-[3rem] p-10 shadow-xl">
<h3 className="text-2xl font-black text-medical-gray-900 mb-8">ارسال پیام مستقیم</h3>
{success ? (
<div className="p-6 bg-emerald-50 border border-emerald-200 text-emerald-800 rounded-2xl text-center space-y-3">
<CheckCircle2 className="w-12 h-12 text-emerald-600 mx-auto" />
<h4 className="text-lg font-black">پیام شما با موفقیت ثبت شد</h4>
<p className="text-sm font-medium leading-relaxed">
پیامک تایید به شماره شما ارسال شد. کارشناسان کنینا به زودی با شما تماس خواهند گرفت.
</p>
<button
onClick={() => setSuccess(false)}
className="mt-4 px-6 py-2 bg-emerald-600 text-white rounded-xl text-xs font-black"
>
ارسال پیام جدید
</button>
</div>
) : (
<form onSubmit={handleSubmit} className="space-y-6">
{error && (
<div className="p-4 bg-rose-50 border border-rose-200 text-rose-700 text-xs font-bold rounded-2xl">
{error}
</div>
)}
<div className="grid md:grid-cols-2 gap-6">
<div className="space-y-2">
<label className="text-xs font-black text-medical-gray-500">
نام و نام خانوادگی *
</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl p-4 text-sm font-bold focus:outline-none focus:ring-2 focus:ring-canina-blue/20"
placeholder="مثال: علی محمدی"
required
/>
</div>
<div className="space-y-2">
<label className="text-xs font-black text-medical-gray-500">شماره موبایل *</label>
<input
type="text"
value={phone}
onChange={(e) => setPhone(e.target.value)}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl p-4 text-sm font-bold text-left focus:outline-none focus:ring-2 focus:ring-canina-blue/20"
dir="ltr"
placeholder="09123456789"
required
/>
</div>
</div>
<div className="space-y-2">
<label className="text-xs font-black text-medical-gray-500">موضوع پیام</label>
<input
type="text"
value={subject}
onChange={(e) => setSubject(e.target.value)}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl p-4 text-sm font-bold focus:outline-none focus:ring-2 focus:ring-canina-blue/20"
placeholder="مثال: مشاوره تخصصی مکمل یا خرید عمده"
/>
</div>
<div className="space-y-2">
<label className="text-xs font-black text-medical-gray-500">متن پیام *</label>
<textarea
rows={4}
value={message}
onChange={(e) => setMessage(e.target.value)}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl p-4 text-sm font-bold focus:outline-none focus:ring-2 focus:ring-canina-blue/20"
placeholder="متن درخواست یا پیام خود را بنویسید..."
required
></textarea>
</div>
<button
type="submit"
disabled={loading}
className="w-full bg-canina-blue text-white py-4 rounded-2xl font-black flex items-center justify-center gap-2 hover:shadow-xl hover:shadow-canina-blue/20 transition-all disabled:opacity-50"
>
<Send className="w-5 h-5 rotate-180" />
{loading ? "در حال ثبت..." : "ارسال پیام"}
</button>
</form>
)}
</div>
</div>
);
}