canina/frontend/application/components/SmartAdvisor.tsx
parsa aghaei 5e6e25390e
Some checks failed
E2E Playwright Tests / Run Full E2E & Security Suites (push) Failing after 6s
Deploy Canina / deploy (push) Has been cancelled
fix(images): restore direct upload loading to fix 502, fix StatCounter CLS and SmartAdvisor button contrast
2026-09-02 15:09:54 +03:30

641 lines
36 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 React, { useState, useEffect } from "react";
import Link from "next/link";
import { motion, AnimatePresence } from "motion/react";
import { useSettingsStore } from "../lib/store/settingsStore";
import {
Dog,
Cat,
ChevronLeft,
ChevronRight,
ShieldCheck,
Activity,
Pill,
Sparkle,
Check,
Download
} from "lucide-react";
import { cn } from "../lib/utils";
import { PRODUCTS } from "../lib/data/products";
import { productService } from "../lib/services/productService";
import { useRouter } from "next/navigation";
import { useUserStore } from "../lib/store/userStore";
import { useUIStore } from "../lib/store/uiStore";
import { usePetStore } from "../lib/store/usePetStore";
import api from "../lib/services/api";
interface SmartAdvisorProps {
onComplete?: (data: Record<string, unknown>) => void;
}
const CURRENT_SYMPTOMS = [
{ id: "none_symptom", label: "هیچ‌کدام (سلامت کامل و بدون علامت)", condition: "هیچ‌کدام (سلامت کامل)" },
{ id: "joint_pain", label: "درد مفاصل و لنگیدن", condition: "درد مفاصل" },
{ id: "hair_loss", label: "ریزش مو، خارش و خشکی پوست", condition: "ریزش مو" },
{ id: "diarrhea", label: "اسهال، یبوست و مشکلات گوارشی", condition: "اسهال" },
{ id: "appetite", label: "بی‌اشتهایی و کاهش وزن", condition: "بی‌اشتهایی" },
{ id: "dental", label: "جرم دندان و بوی بد دهان", condition: "جرم دندان" },
{ id: "eye", label: "ترشحات یا مشکلات چشم", condition: "چشم" },
{ id: "puppy_growth", label: "رشد سریع و تعادل استخوانی", condition: "رشد سریع توله‌سگ" },
{ id: "tendon", label: "سفتی عضلات و ضعف تاندون", condition: "تاندون" },
];
const MEDICAL_HISTORIES = [
{ id: "none_history", label: "هیچ‌کدام (بدون سابقه بیماری و جراحی)", condition: "هیچ‌کدام (بدون سابقه بیماری)" },
{ id: "joint_surgery", label: "سابقه جراحی مفاصل/استخوان", condition: "جراحی مفاصل" },
{ id: "recent_birth", label: "زایمان اخیر / شیردهی فعال", condition: "زایمان اخیر" },
{ id: "pregnancy", label: "دوران بارداری", condition: "بارداری" },
{ id: "weakness", label: "ضعف بعد از بیماری / نقاهت", condition: "ضعف بعد از بیماری" },
{ id: "heart", label: "نارسایی یا حساسیت قلبی", condition: "نارسایی قلبی" },
{ id: "parasite", label: "سابقه آلودگی انگلی", condition: "آلودگی انگلی" },
];
export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorProps & { rules?: unknown[] }) {
const router = useRouter();
const { isLoggedIn } = useUserStore();
const setLoginModalOpen = useUIStore(state => state.setLoginModalOpen);
const { addPet, setActivePet } = usePetStore();
const getText = useSettingsStore(state => state.getText);
const [advisorRules, setAdvisorRules] = useState<unknown[]>(rules || []);
useEffect(() => {
if (rules && rules.length > 0) {
setAdvisorRules(rules);
return;
}
let isMounted = true;
api.get('/smart-advisor/rules')
.then(res => {
if (isMounted && Array.isArray(res.data)) {
setAdvisorRules(res.data);
}
})
.catch(err => console.error("[SmartAdvisor] Failed to fetch rules:", err));
return () => {
isMounted = false;
};
}, [rules?.length]);
const [step, setStep] = useState(1);
// Step 1 Data
const [name, setName] = useState("");
const [type, setType] = useState<"سگ" | "گربه">("سگ");
const [breed, setBreed] = useState("");
const [showError, setShowError] = useState(false);
const [shake, setShake] = useState(false);
// Step 2 Data
const [age, setAge] = useState<number>(3);
const [weight, setWeight] = useState<number>(10);
const [activityLevel, setActivityLevel] = useState<"کم" | "متوسط" | "زیاد">("متوسط");
// Step 3 Data (Symptoms) & Step 4 Data (History) - default to none
const [currentSymptoms, setCurrentSymptoms] = useState<string[]>(["هیچ‌کدام (سلامت کامل)"]);
const [medicalConditions, setMedicalConditions] = useState<string[]>(["هیچ‌کدام (بدون سابقه بیماری)"]);
const toggleSymptom = (condition: string) => {
if (condition === "هیچ‌کدام (سلامت کامل)") {
setCurrentSymptoms(["هیچ‌کدام (سلامت کامل)"]);
return;
}
setCurrentSymptoms(prev => {
const filtered = prev.filter(c => c !== "هیچ‌کدام (سلامت کامل)");
if (filtered.includes(condition)) {
const next = filtered.filter(c => c !== condition);
return next.length === 0 ? ["هیچ‌کدام (سلامت کامل)"] : next;
} else {
return [...filtered, condition];
}
});
};
const toggleMedicalHistory = (condition: string) => {
if (condition === "هیچ‌کدام (بدون سابقه بیماری)") {
setMedicalConditions(["هیچ‌کدام (بدون سابقه بیماری)"]);
return;
}
setMedicalConditions(prev => {
const filtered = prev.filter(c => c !== "هیچ‌کدام (بدون سابقه بیماری)");
if (filtered.includes(condition)) {
const next = filtered.filter(c => c !== condition);
return next.length === 0 ? ["هیچ‌کدام (بدون سابقه بیماری)"] : next;
} else {
return [...filtered, condition];
}
});
};
const handleNext = () => {
if (step === 1) {
if (!name.trim() || !breed.trim()) {
setShowError(true);
setShake(true);
setTimeout(() => setShake(false), 500);
return;
}
}
setStep(s => s + 1);
};
const handleBack = () => setStep(s => s - 1);
const calculateRecommendation = async () => {
const rawConditions = Array.from(new Set([...currentSymptoms, ...medicalConditions]));
const combinedConditions = rawConditions.filter(c => !c.includes("هیچ‌کدام"));
let matchedProd: Record<string, unknown> | null = null;
// First, check fetched advisor rules
if (advisorRules && advisorRules.length > 0) {
const foundRule = advisorRules.find((r) => {
const ruleObj = r as Record<string, unknown>;
const targetPetType = ruleObj.targetPetType as string | undefined;
const condition = ruleObj.condition as string | undefined;
const petMatch = !targetPetType || targetPetType === "هر دو" || targetPetType === type;
const conditionMatch = combinedConditions.some(c => condition?.includes(c) || c.includes(condition || ''));
return petMatch && conditionMatch;
}) as Record<string, unknown> | undefined;
if (foundRule && foundRule.product) {
matchedProd = foundRule.product as Record<string, unknown>;
}
}
// Second, query dynamic products API
if (!matchedProd) {
try {
const liveRes = await productService.getProducts({ petType: type, limit: 50 });
if (liveRes.data && liveRes.data.length > 0) {
const found = liveRes.data.find(p => {
const matchPet = p.suitableFor === "هر دو" || p.suitableFor === type;
const matchSymptom = p.symptoms?.some((s: string) => combinedConditions.some(c => s.includes(c) || c.includes(s)));
return matchPet && matchSymptom;
});
matchedProd = (found || liveRes.data[0]) as unknown as Record<string, unknown>;
}
} catch (e) {
console.error("[SmartAdvisor] Dynamic product fetch failed, using fallback", e);
}
}
if (!matchedProd) {
const fallback = PRODUCTS.find(p => p.suitableFor === "هر دو" || p.suitableFor === type) || PRODUCTS[0];
matchedProd = fallback as unknown as Record<string, unknown>;
}
};
const handleSubmit = () => {
const rawConditions = Array.from(new Set([...currentSymptoms, ...medicalConditions]));
const combinedConditions = rawConditions.filter(c => !c.includes("هیچ‌کدام"));
const data = {
name, type, breed, age, weight, activityLevel, medicalConditions: combinedConditions
};
calculateRecommendation();
if (onComplete) {
onComplete(data);
} else {
if (!isLoggedIn) {
setLoginModalOpen(true, data);
} else {
const newPet = { ...data, id: Date.now().toString(), reminders: [], logs: [], consumptions: [] };
addPet(newPet);
setActivePet(newPet.id);
router.push('/profile');
}
}
};
return (
<section id="canino-advisor" className="py-8 sm:py-16 bg-gradient-to-b from-white via-medical-gray-50/50 to-white">
<div className="max-w-5xl mx-auto px-4">
{/* Header Title */}
<div className="text-center mb-6 sm:mb-10">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
className="inline-flex items-center gap-2 px-3.5 py-1.5 sm:px-4 sm:py-2 bg-canina-blue/5 rounded-full mb-3 sm:mb-4 border border-canina-blue/10"
>
<Sparkle className="w-4 h-4 text-canina-blue animate-spin" />
<span suppressHydrationWarning className="text-canina-blue text-[11px] sm:text-xs font-black uppercase tracking-widest font-vazir">{getText('advisor_badge', "سیستم پایش و تجویز هوشمند")}</span>
</motion.div>
<h2 suppressHydrationWarning className="text-2xl sm:text-4xl lg:text-5xl font-black text-medical-gray-900 mb-2 sm:mb-4 font-lalezar tracking-wide">{getText('advisor_title', "دستیار سلامت و الگوریتم پایش کنینا")}</h2>
<p suppressHydrationWarning className="text-medical-gray-600 font-medium text-xs sm:text-base font-shabnam max-w-2xl mx-auto leading-relaxed">
{getText('advisor_subtitle', "با ثبت اطلاعات همدم خود در ۴ قدم ساده، از الگوریتم علمی کنینا برای تجویز دقیق مکمل و پایش سلامت بهره‌مند شوید.")}
</p>
<div className="mt-4 flex justify-center">
<Link
href="/catalog"
className="inline-flex items-center gap-2 px-4 py-2 bg-medical-gray-50 border border-medical-gray-200 rounded-xl text-medical-gray-600 text-xs font-bold hover:bg-canina-blue hover:text-white transition-all shadow-sm"
>
<Download className="w-4 h-4" />
<span>مشاهده کاتالوگ و جدول دوز آلمان</span>
</Link>
</div>
</div>
{/* Value Proposition Cards (Explaining Why & How) */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
className="grid grid-cols-1 md:grid-cols-3 gap-4 sm:gap-6 mb-8 sm:mb-12"
>
<div className="bg-white p-4 sm:p-6 rounded-2xl sm:rounded-[2.5rem] border border-medical-gray-200/80 shadow-md sm:shadow-lg hover:shadow-xl transition-all group flex flex-col justify-between">
<div>
<div className="flex items-center gap-3 sm:block mb-2 sm:mb-0">
<div className="w-9 h-9 sm:w-12 sm:h-12 bg-canina-blue/10 rounded-xl sm:rounded-2xl flex items-center justify-center text-canina-blue sm:mb-4 group-hover:bg-canina-blue group-hover:text-white transition-all shadow-sm flex-shrink-0">
<Pill className="w-5 h-5 sm:w-6 sm:h-6" />
</div>
<h3 className="text-base sm:text-lg font-black text-medical-gray-900 sm:mb-2 font-vazir">چرا ثبت شناسنامه؟</h3>
</div>
<p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir">
مکملهای دارویی کنینا غلیظ و تخصصی هستند؛ الگوریتم هوشمند ما بر اساس سن، وزن و جثه پت شما، دوز دقیق مصرفی روزانه را محاسبه میکند.
</p>
</div>
<div className="mt-3 sm:mt-4 pt-3 sm:pt-4 border-t border-medical-gray-100 text-[10px] font-black text-canina-blue flex items-center gap-1 font-vazir">
<Check className="w-3.5 h-3.5" />
تضمین ایمنی و عدم اوردوز
</div>
</div>
<div className="bg-white p-4 sm:p-6 rounded-2xl sm:rounded-[2.5rem] border border-medical-gray-200/80 shadow-md sm:shadow-lg hover:shadow-xl transition-all group flex flex-col justify-between">
<div>
<div className="flex items-center gap-3 sm:block mb-2 sm:mb-0">
<div className="w-9 h-9 sm:w-12 sm:h-12 bg-canina-blue/10 rounded-xl sm:rounded-2xl flex items-center justify-center text-canina-blue sm:mb-4 group-hover:bg-canina-blue group-hover:text-white transition-all shadow-sm flex-shrink-0">
<Activity className="w-5 h-5 sm:w-6 sm:h-6" />
</div>
<h3 className="text-base sm:text-lg font-black text-medical-gray-900 sm:mb-2 font-vazir">تطبیق علائم بالینی</h3>
</div>
<p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir">
با انتخاب علائمی مثل لنگیدن یا ریزش مو، دقیقترین راهکار مکمل آلمانی به همراه دلایل علمی به شما پیشنهاد میشود.
</p>
</div>
<div className="mt-3 sm:mt-4 pt-3 sm:pt-4 border-t border-medical-gray-100 text-[10px] font-black text-canina-blue flex items-center gap-1 font-vazir">
<Check className="w-3.5 h-3.5" />
پیشنهاد هدفمند و تخصصی
</div>
</div>
<div className="bg-white p-4 sm:p-6 rounded-2xl sm:rounded-[2.5rem] border border-medical-gray-200/80 shadow-md sm:shadow-lg hover:shadow-xl transition-all group flex flex-col justify-between">
<div>
<div className="flex items-center gap-3 sm:block mb-2 sm:mb-0">
<div className="w-9 h-9 sm:w-12 sm:h-12 bg-canina-blue/10 rounded-xl sm:rounded-2xl flex items-center justify-center text-canina-blue sm:mb-4 group-hover:bg-canina-blue group-hover:text-white transition-all shadow-sm flex-shrink-0">
<ShieldCheck className="w-5 h-5 sm:w-6 sm:h-6" />
</div>
<h3 className="text-base sm:text-lg font-black text-medical-gray-900 sm:mb-2 font-vazir">پایش موجودی و یادآور</h3>
</div>
<p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir">
زمانهای مصرف مکملها تنظیم شده و سیستم قبل از اتمام دوره درمانی، هشدار شارژ مجدد ارسال خواهد کرد.
</p>
</div>
<div className="mt-3 sm:mt-4 pt-3 sm:pt-4 border-t border-medical-gray-100 text-[10px] font-black text-canina-blue flex items-center gap-1 font-vazir">
<Check className="w-3.5 h-3.5" />
تکمیل منظم دوره درمان
</div>
</div>
</motion.div>
<div className="bg-medical-gray-50 rounded-[2.5rem] border border-medical-gray-200/80 p-5 sm:p-8 lg:p-10 shadow-xl shadow-medical-gray-200/40 relative overflow-hidden">
{/* Progress Indicator */}
<div className="absolute top-0 left-0 w-full h-1.5 bg-medical-gray-200">
<motion.div
className="h-full bg-canina-blue"
initial={{ width: "0%" }}
animate={{ width: `${(step / 4) * 100}%` }}
transition={{ duration: 0.4 }}
/>
</div>
<AnimatePresence mode="wait">
{step === 1 && (
<motion.div
key="step1"
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
className="space-y-6"
>
<div className="text-center">
<h3 className="text-xl sm:text-2xl font-black text-medical-gray-900 mb-1.5 font-vazir tracking-tight">{getText('advisor_step1_title', "گام اول: مشخصات پت")}</h3>
<p className="text-xs sm:text-sm text-medical-gray-500 font-bold font-vazir">{getText('advisor_step1_desc', "همدم شما رو با چه اسمی صدا می‌زنید؟")}</p>
</div>
<div className="grid grid-cols-2 gap-3 sm:gap-4 max-w-md mx-auto">
<button
type="button"
onClick={() => setType("سگ")}
className={`flex flex-col items-center gap-2.5 p-5 sm:p-6 rounded-2xl border-2 transition-all cursor-pointer ${type === "سگ" ? 'border-canina-blue bg-white shadow-md shadow-canina-blue/10 text-canina-blue scale-102' : 'border-medical-gray-200 bg-white text-medical-gray-500 hover:border-canina-blue/30'}`}
>
<Dog className="w-8 h-8 sm:w-10 sm:h-10" />
<span className="text-sm sm:text-base font-black font-vazir">سگ</span>
</button>
<button
type="button"
onClick={() => setType("گربه")}
className={`flex flex-col items-center gap-2.5 p-5 sm:p-6 rounded-2xl border-2 transition-all cursor-pointer ${type === "گربه" ? 'border-canina-blue bg-white shadow-md shadow-canina-blue/10 text-canina-blue scale-102' : 'border-medical-gray-200 bg-white text-medical-gray-500 hover:border-canina-blue/30'}`}
>
<Cat className="w-8 h-8 sm:w-10 sm:h-10" />
<span className="text-sm sm:text-base font-black font-vazir">گربه</span>
</button>
</div>
<div className="grid md:grid-cols-2 gap-4 max-w-xl mx-auto">
<div className="space-y-1.5">
<label className="text-xs font-black text-medical-gray-600 pr-1">{getText('advisor_pet_name_label', "نام پت")}</label>
<input
type="text"
value={name}
onChange={e => {
setName(e.target.value);
if (e.target.value.trim() && breed.trim()) setShowError(false);
}}
placeholder={getText('advisor_pet_name_placeholder', "مثال: لوسی")}
className={cn(
"w-full bg-white border rounded-xl py-3 px-4 focus:ring-2 outline-none font-bold text-sm font-vazir placeholder-medical-gray-400 text-medical-gray-900 transition-all",
showError && !name.trim()
? "border-red-500 focus:ring-red-500/30"
: "border-medical-gray-200 focus:ring-canina-blue/30 focus:border-canina-blue"
)}
/>
</div>
<div className="space-y-1.5">
<label className="text-xs font-black text-medical-gray-600 pr-1">{getText('advisor_pet_breed_label', "نژاد")}</label>
<input
type="text"
value={breed}
onChange={e => {
setBreed(e.target.value);
if (name.trim() && e.target.value.trim()) setShowError(false);
}}
placeholder={getText('advisor_pet_breed_placeholder', "مثال: ژرمن شپرد")}
className={cn(
"w-full bg-white border rounded-xl py-3 px-4 focus:ring-2 outline-none font-bold text-sm font-vazir placeholder-medical-gray-400 text-medical-gray-900 transition-all",
showError && !breed.trim()
? "border-red-500 focus:ring-red-500/30"
: "border-medical-gray-200 focus:ring-canina-blue/30 focus:border-canina-blue"
)}
/>
</div>
</div>
<div className="max-w-md mx-auto pt-2">
<motion.button
type="button"
onClick={handleNext}
animate={shake ? { x: [-10, 10, -10, 10, -5, 5, -2, 2, 0] } : { x: 0 }}
transition={{ duration: 0.4 }}
className={cn(
"w-full whitespace-nowrap px-6 sm:px-10 py-3 sm:py-4 rounded-full font-bold text-sm sm:text-base focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none transition-all flex items-center justify-center gap-2 group font-vazir min-h-[48px] shadow-md cursor-pointer",
(!name.trim() || !breed.trim())
? "bg-slate-700 text-white shadow-none"
: "bg-canina-blue text-white hover:bg-canina-blue/90 hover:shadow-xl shadow-canina-blue/20"
)}
>
<span>{getText('advisor_submit_btn', "ثبت هویت و ادامه")}</span>
<ChevronLeft className="w-4 h-4 group-hover:-translate-x-1 transition-transform" />
</motion.button>
{showError && (!name.trim() || !breed.trim()) && (
<p className="text-center text-xs font-bold text-red-500 mt-2 font-vazir animate-pulse">
{getText('advisor_validation_warning', "⚠️ لطفاً ابتدا نام و نژاد پت را وارد کنید.")}
</p>
)}
</div>
</motion.div>
)}
{step === 2 && (
<motion.div
key="step2"
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
className="space-y-6 max-w-xl mx-auto"
>
<div className="text-center">
<h3 className="text-xl sm:text-2xl font-black text-medical-gray-900 mb-1.5 font-vazir tracking-tight">{getText('advisor_step2_title', "گام دوم: پایش فیزیکی")}</h3>
<p className="text-xs sm:text-sm text-medical-gray-500 font-bold font-vazir">{getText('advisor_step2_desc', "اطلاعات فیزیکی به دوزبندی دقیق مکمل‌ها کمک می‌کند")}</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{/* Age Input Box */}
<div className="bg-white p-3.5 rounded-2xl border border-medical-gray-200 shadow-xs space-y-2">
<label className="block text-center text-xs font-black text-medical-gray-700 font-vazir">{getText('advisor_age_label', "سن حیوان (سال)")}</label>
<div className="flex items-center justify-between gap-1.5 bg-medical-gray-50 rounded-xl p-1 border border-medical-gray-200">
<button
type="button"
onClick={() => setAge(Math.max(0, age - 1))}
className="w-9 h-9 shrink-0 flex items-center justify-center bg-white rounded-lg text-medical-gray-800 hover:bg-canina-blue hover:text-white transition-all shadow-xs font-black text-base cursor-pointer"
>
-
</button>
<div className="flex-1 flex items-center justify-center gap-1" dir="ltr">
<input
type="text"
inputMode="numeric"
pattern="[0-9]*"
value={age === 0 ? '' : age.toString()}
onChange={(e) => {
const val = e.target.value.replace(/[^0-9]/g, '');
setAge(val === '' ? 0 : Math.min(30, parseInt(val, 10)));
}}
className="w-14 text-center text-lg font-black text-canina-blue font-mono outline-none bg-transparent"
/>
<span className="text-[11px] font-bold text-medical-gray-400 font-vazir">سال</span>
</div>
<button
type="button"
onClick={() => setAge(Math.min(30, age + 1))}
className="w-9 h-9 shrink-0 flex items-center justify-center bg-white rounded-lg text-medical-gray-800 hover:bg-canina-blue hover:text-white transition-all shadow-xs font-black text-base cursor-pointer"
>
+
</button>
</div>
</div>
{/* Weight Input Box */}
<div className="bg-white p-3.5 rounded-2xl border border-medical-gray-200 shadow-xs space-y-2">
<label className="block text-center text-xs font-black text-medical-gray-700 font-vazir">{getText('advisor_weight_label', "وزن حیوان (کیلوگرم)")}</label>
<div className="flex items-center justify-between gap-1.5 bg-medical-gray-50 rounded-xl p-1 border border-medical-gray-200">
<button
type="button"
onClick={() => setWeight(Math.max(1, weight - 1))}
className="w-9 h-9 shrink-0 flex items-center justify-center bg-white rounded-lg text-medical-gray-800 hover:bg-canina-blue hover:text-white transition-all shadow-xs font-black text-base cursor-pointer"
>
-
</button>
<div className="flex-1 flex items-center justify-center gap-1" dir="ltr">
<input
type="text"
inputMode="numeric"
pattern="[0-9]*"
value={weight === 0 ? '' : weight.toString()}
onChange={(e) => {
const val = e.target.value.replace(/[^0-9]/g, '');
setWeight(val === '' ? 0 : Math.min(120, parseInt(val, 10)));
}}
className="w-14 text-center text-lg font-black text-canina-blue font-mono outline-none bg-transparent"
/>
<span className="text-[11px] font-bold text-medical-gray-400 font-vazir">kg</span>
</div>
<button
type="button"
onClick={() => setWeight(Math.min(120, weight + 1))}
className="w-9 h-9 shrink-0 flex items-center justify-center bg-white rounded-lg text-medical-gray-800 hover:bg-canina-blue hover:text-white transition-all shadow-xs font-black text-base cursor-pointer"
>
+
</button>
</div>
</div>
</div>
{/* Activity Level */}
<div className="space-y-2">
<label className="block text-center text-xs font-black text-medical-gray-600 font-vazir">{getText('advisor_activity_label', "سطح فعالیت روزانه")}</label>
<div className="grid grid-cols-3 gap-2">
{["کم", "متوسط", "زیاد"].map(level => (
<button
key={level}
type="button"
onClick={() => setActivityLevel(level as "کم" | "متوسط" | "زیاد")}
className={`py-2.5 rounded-xl border-2 transition-all font-bold text-xs sm:text-sm cursor-pointer ${activityLevel === level ? 'border-canina-blue bg-white text-canina-blue shadow-sm' : 'border-transparent bg-white/70 text-medical-gray-500 hover:bg-white'}`}
>
{level}
</button>
))}
</div>
</div>
{/* Buttons (matching Hero layout) */}
<div className="whitespace-nowrap flex items-center justify-between gap-3 pt-3">
<button
type="button"
onClick={handleBack}
className="whitespace-nowrap bg-white border-2 border-medical-gray-300 text-medical-gray-700 px-4 sm:px-6 py-2.5 sm:py-3.5 rounded-full font-bold text-xs sm:text-sm hover:bg-medical-gray-50 transition-all flex items-center gap-1.5 cursor-pointer"
>
<ChevronRight className="w-4 h-4" />
<span>{getText('advisor_back', "قبلی")}</span>
</button>
<button
type="button"
onClick={handleNext}
className="whitespace-nowrap bg-canina-blue text-white px-5 sm:px-8 py-2.5 sm:py-3.5 rounded-full font-bold text-xs sm:text-sm hover:bg-canina-blue/90 hover:shadow-lg transition-all flex items-center gap-1.5 shadow-md shadow-canina-blue/20 cursor-pointer"
>
<span>{getText('advisor_next_symptoms', "علائم بالینی")}</span>
<ChevronLeft className="w-4 h-4" />
</button>
</div>
</motion.div>
)}
{step === 3 && (
<motion.div
key="step3"
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
className="space-y-5 max-w-2xl mx-auto"
>
<div className="text-center">
<h3 className="text-xl sm:text-2xl font-black text-medical-gray-900 mb-1 font-vazir tracking-tight">{getText('advisor_step3_symptoms_title', "گام سوم: علائم بالینی فعلی")}</h3>
<p className="text-xs sm:text-sm text-medical-gray-500 font-bold font-vazir">{getText('advisor_step3_symptoms_desc', "آیا همدم شما در حال حاضر علائم زیر را دارد؟")}</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2.5 max-h-[50vh] sm:max-h-none overflow-y-auto pr-1">
{CURRENT_SYMPTOMS.map((opt) => (
<button
key={opt.id}
type="button"
onClick={() => toggleSymptom(opt.condition)}
className={`flex items-center gap-3 p-3.5 rounded-xl border transition-all text-right cursor-pointer ${currentSymptoms.includes(opt.condition) ? 'border-canina-blue bg-canina-blue/5 shadow-xs text-canina-blue' : 'border-medical-gray-200 bg-white text-medical-gray-700 hover:border-canina-blue/40'}`}
>
<div className={`w-5 h-5 rounded-md flex items-center justify-center border shrink-0 ${currentSymptoms.includes(opt.condition) ? 'bg-canina-blue border-canina-blue text-white' : 'border-medical-gray-300 bg-white'}`}>
{currentSymptoms.includes(opt.condition) && <Check className="w-3.5 h-3.5 stroke-[3]" />}
</div>
<span className="text-xs sm:text-sm font-bold font-vazir leading-tight">{opt.label}</span>
</button>
))}
</div>
<div className="whitespace-nowrap flex items-center justify-between gap-3 pt-3">
<button
type="button"
onClick={handleBack}
className="whitespace-nowrap bg-white border-2 border-medical-gray-300 text-medical-gray-700 px-4 sm:px-6 py-2.5 sm:py-3.5 rounded-full font-bold text-xs sm:text-sm hover:bg-medical-gray-50 transition-all flex items-center gap-1.5 cursor-pointer"
>
<ChevronRight className="w-4 h-4" />
<span>{getText('advisor_back', "قبلی")}</span>
</button>
<button
type="button"
onClick={handleNext}
className="whitespace-nowrap bg-canina-blue text-white px-5 sm:px-8 py-2.5 sm:py-3.5 rounded-full font-bold text-xs sm:text-sm hover:bg-canina-blue/90 hover:shadow-lg transition-all flex items-center gap-1.5 shadow-md shadow-canina-blue/20 cursor-pointer"
>
<span>{getText('advisor_next_history', "سوابق پزشکی")}</span>
<ChevronLeft className="w-4 h-4" />
</button>
</div>
</motion.div>
)}
{step === 4 && (
<motion.div
key="step4"
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
className="space-y-5 max-w-2xl mx-auto"
>
<div className="text-center">
<h3 className="text-xl sm:text-2xl font-black text-medical-gray-900 mb-1 font-vazir tracking-tight">{getText('advisor_step4_history_title', "گام چهارم: سوابق پزشکی")}</h3>
<p className="text-xs sm:text-sm text-medical-gray-500 font-bold font-vazir">{getText('advisor_step4_history_desc', "در صورت وجود سابقه جراحی، بارداری یا نارسایی، آن را مشخص کنید")}</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2.5 max-h-[50vh] sm:max-h-none overflow-y-auto pr-1">
{MEDICAL_HISTORIES.map((opt) => (
<button
key={opt.id}
type="button"
onClick={() => toggleMedicalHistory(opt.condition)}
className={`flex items-center gap-3 p-3.5 rounded-xl border transition-all text-right cursor-pointer ${medicalConditions.includes(opt.condition) ? 'border-canina-blue bg-canina-blue/5 shadow-xs text-canina-blue' : 'border-medical-gray-200 bg-white text-medical-gray-700 hover:border-canina-blue/40'}`}
>
<div className={`w-5 h-5 rounded-md flex items-center justify-center border shrink-0 ${medicalConditions.includes(opt.condition) ? 'bg-canina-blue border-canina-blue text-white' : 'border-medical-gray-300 bg-white'}`}>
{medicalConditions.includes(opt.condition) && <Check className="w-3.5 h-3.5 stroke-[3]" />}
</div>
<span className="text-xs sm:text-sm font-bold font-vazir leading-tight">{opt.label}</span>
</button>
))}
</div>
<div className="whitespace-nowrap flex items-center justify-between gap-3 pt-3">
<button
type="button"
onClick={handleBack}
className="whitespace-nowrap bg-white border-2 border-medical-gray-300 text-medical-gray-700 px-4 sm:px-6 py-2.5 sm:py-3.5 rounded-full font-bold text-xs sm:text-sm hover:bg-medical-gray-50 transition-all flex items-center gap-1.5 cursor-pointer"
>
<ChevronRight className="w-4 h-4" />
<span>{getText('advisor_back', "قبلی")}</span>
</button>
<button
type="button"
onClick={handleSubmit}
className="whitespace-nowrap bg-emerald-600 text-white px-6 sm:px-9 py-2.5 sm:py-3.5 rounded-full font-bold text-xs sm:text-sm hover:bg-emerald-700 hover:shadow-lg transition-all flex items-center gap-1.5 shadow-md shadow-emerald-600/20 cursor-pointer"
>
<span>{getText('advisor_complete', "صدور شناسنامه و پیشنهاد")}</span>
<ChevronLeft className="w-4 h-4" />
</button>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
</div>
</section>
);
}