canina/frontend/application/components/UserDashboard.tsx

735 lines
44 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 } from "react";
import { motion, AnimatePresence } from "motion/react";
import { User, ShoppingBag, Wallet, MapPin, LogOut, ChevronRight, Package, Calendar, UserCircle, ShoppingCart, Trash2, Edit2, Phone, Hash, CheckCircle2, ArrowUpCircle, ArrowDownCircle, Info, Clock, CheckCircle, Heart, Sparkles, MessageSquare, Send, Stethoscope, FileText } from "lucide-react";
import { OrderRowSkeleton } from "./Skeleton";
import { useUserStore, Address } from "../lib/store/userStore";
import { useCartStore } from "../lib/store/cartStore";
import { toPersian, cn } from "../lib/utils";
import { toast } from "sonner";
import OrderDetailsModal from "./OrderDetailsModal";
import AddressModal from "./AddressModal";
import DeleteConfirmModal from "./DeleteConfirmModal";
import TopUpModal from "./TopUpModal";
import { useRouter } from 'next/navigation';
export default function UserDashboard() {
const router = useRouter();
const { profile, isLoggedIn, logout, addAddress, updateAddress, deleteAddress, setDefaultAddress, topUpWallet } = useUserStore();
React.useEffect(() => {
if (!isLoggedIn && typeof window !== "undefined") {
router.push("/");
toast.error("برای دسترسی به داشبورد لطفاً ابتدا وارد حساب کاربری خود شوید.");
}
}, [isLoggedIn, router]);
const { orders } = useCartStore();
const [activeTab, setActiveTab] = React.useState<"profile" | "orders" | "wallet" | "addresses" | "tickets">("profile");
const [isLoadingOrders, setIsLoadingOrders] = useState(false);
// Fetch fresh profile data (which includes orders) whenever orders tab is opened
React.useEffect(() => {
if (activeTab === "orders") {
setIsLoadingOrders(true);
useUserStore.getState().fetchProfile().finally(() => setIsLoadingOrders(false));
}
}, [activeTab]);
const [selectedOrder, setSelectedOrder] = useState<any>(null);
// Address State
const [isAddressModalOpen, setIsAddressModalOpen] = useState(false);
const [editingAddress, setEditingAddress] = useState<Address | null>(null);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [addressToDelete, setAddressToDelete] = useState<Address | null>(null);
// Wallet State
const [isTopUpModalOpen, setIsTopUpModalOpen] = useState(false);
// Profile State
const [isEditing, setIsEditing] = useState(false);
const [isSavingProfile, setIsSavingProfile] = useState(false);
const [profileForm, setProfileForm] = useState({
firstName: profile.firstName || "",
lastName: profile.lastName || "",
email: profile.email || "",
mobile: profile.mobile || ""
});
// Sync profile data on change
React.useEffect(() => {
setProfileForm({
firstName: profile.firstName || "",
lastName: profile.lastName || "",
email: profile.email || "",
mobile: profile.mobile || ""
});
}, [profile]);
const handleSaveProfile = async (e: React.FormEvent) => {
e.preventDefault();
if (!isEditing) return;
const cleanPhone = profileForm.mobile.trim();
if (!/^09\d{9}$/.test(cleanPhone)) {
toast.error("شماره موبایل وارد شده معتبر نیست (باید ۱۱ رقم باشد و با ۰۹ شروع شود)");
return;
}
setIsSavingProfile(true);
try {
await useUserStore.getState().updateProfile({
firstName: profileForm.firstName,
lastName: profileForm.lastName,
email: profileForm.email,
mobile: cleanPhone
});
setIsEditing(false);
toast.success("اطلاعات کاربری با موفقیت ویرایش شد");
} catch (err: any) {
toast.error(err.message || "خطا در ویرایش اطلاعات");
} finally {
setIsSavingProfile(false);
}
};
const handleLogout = () => {
logout();
router.push('/');
};
const handleSaveAddress = async (addr: Address) => {
try {
if (editingAddress) {
await updateAddress(addr.id, addr);
} else {
await addAddress(addr);
}
} catch (err) {
toast.error("خطا در ثبت آدرس");
}
setEditingAddress(null);
};
const handleDeleteClick = (addr: Address) => {
setAddressToDelete(addr);
setIsDeleteModalOpen(true);
};
const handleConfirmDelete = async () => {
if (addressToDelete) {
try {
await deleteAddress(addressToDelete.id);
toast.success("آدرس با موفقیت حذف شد");
} catch (err) {
toast.error("خطا در حذف آدرس");
}
setAddressToDelete(null);
}
};
const handleEditClick = (addr: Address) => {
setEditingAddress(addr);
setIsAddressModalOpen(true);
};
const handleAddClick = () => {
setEditingAddress(null);
setIsAddressModalOpen(true);
};
const tabs = [
{ id: "profile", label: "اطلاعات فردی", icon: <UserCircle className="w-5 h-5" /> },
{ id: "orders", label: "سفارشات من", icon: <Package className="w-5 h-5" /> },
{ id: "wallet", label: "کیف پول", icon: <Wallet className="w-5 h-5" /> },
{ id: "addresses", label: "آدرس‌ها", icon: <MapPin className="w-5 h-5" /> },
{ id: "tickets", label: "پشتیبانی و مشاوره", icon: <MessageSquare className="w-5 h-5" /> },
];
return (
<div className="min-h-screen bg-medical-gray-50 pt-6 sm:pt-12 pb-24 px-3 sm:px-4 font-vazir overflow-x-hidden" dir="rtl">
<div className="max-w-6xl mx-auto w-full">
{/* Breadcrumb */}
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-6 sm:mb-10 overflow-x-auto whitespace-nowrap pb-2 no-scrollbar">
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronRight className="w-2.5 h-2.5 flex-shrink-0" />
<span className="text-canina-blue">پنل کاربری</span>
</div>
<div className="grid lg:grid-cols-12 gap-6 sm:gap-8">
{/* Top User Info & Navigation Tabs */}
<div className="lg:col-span-12">
<div className="bg-white rounded-[1.5rem] sm:rounded-[3rem] border border-medical-gray-200 p-4 sm:p-6 shadow-xl flex flex-col md:flex-row items-stretch md:items-center justify-between gap-4">
<div className="flex items-center gap-3 sm:gap-4">
<div className="w-12 h-12 sm:w-14 sm:h-14 bg-canina-blue rounded-xl sm:rounded-2xl flex items-center justify-center text-white shadow-lg flex-shrink-0">
<User className="w-6 h-6 sm:w-7 sm:h-7" />
</div>
<div className="min-w-0 flex-1">
<h2 className="text-base sm:text-lg font-black text-medical-gray-900 truncate">{profile.firstName} {profile.lastName}</h2>
<p className="text-[11px] sm:text-xs font-bold text-medical-gray-400 truncate">{profile.email}</p>
</div>
</div>
{/* Tab Navigation */}
<div className="grid grid-cols-2 sm:flex sm:flex-wrap items-center gap-2 pt-2 md:pt-0 border-t md:border-t-0 border-medical-gray-100">
{tabs.map(tab => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id as any)}
className={`flex items-center justify-center gap-2 px-3 sm:px-4 py-2.5 sm:py-3 rounded-xl sm:rounded-2xl transition-all font-bold text-xs sm:text-sm ${activeTab === tab.id ? "bg-canina-blue text-white shadow-lg shadow-canina-blue/20" : "text-medical-gray-600 hover:bg-medical-gray-100 bg-medical-gray-50"}`}
>
<div className="flex-shrink-0">{tab.icon}</div>
<span>{tab.label}</span>
</button>
))}
<button
onClick={handleLogout}
className="flex items-center justify-center gap-2 px-3 sm:px-4 py-2.5 sm:py-3 rounded-xl sm:rounded-2xl text-red-500 hover:bg-red-50 transition-all font-bold text-xs sm:text-sm bg-red-50/40 col-span-2 sm:col-span-1"
>
<LogOut className="w-4 h-4 sm:w-5 sm:h-5 flex-shrink-0" />
<span>خروج</span>
</button>
</div>
</div>
</div>
{/* Main Content Area */}
<div className="lg:col-span-8 min-w-0 order-1 lg:order-1">
<motion.div
key={activeTab}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="bg-white rounded-[1.5rem] sm:rounded-[3.5rem] border border-medical-gray-200 p-4 sm:p-10 min-h-[400px] sm:min-h-[600px] shadow-sm overflow-hidden"
>
{activeTab === "profile" && (
<div>
<h3 className="text-2xl font-black text-medical-gray-900 mb-8 italic">اطلاعات فردی</h3>
<form onSubmit={handleSaveProfile} className="space-y-8">
<div className="grid md:grid-cols-2 gap-8">
<div className="space-y-2">
<label htmlFor="firstName" className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block pr-4">نام</label>
<input
autoFocus={isEditing}
type="text"
id="firstName"
name="firstName"
autoComplete="given-name"
required
readOnly={!isEditing}
value={isEditing ? profileForm.firstName : profile.firstName}
onChange={e => setProfileForm({ ...profileForm, firstName: e.target.value })}
className={cn(
"w-full border p-4 rounded-2xl font-bold outline-none transition-all",
isEditing
? "bg-white border-canina-blue/30 focus:ring-2 focus:ring-canina-blue/20"
: "bg-medical-gray-50 border-medical-gray-100"
)}
/>
</div>
<div className="space-y-2">
<label htmlFor="lastName" className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block pr-4">نام خانوادگی</label>
<input
type="text"
id="lastName"
name="lastName"
autoComplete="family-name"
required
readOnly={!isEditing}
value={isEditing ? profileForm.lastName : profile.lastName}
onChange={e => setProfileForm({ ...profileForm, lastName: e.target.value })}
className={cn(
"w-full border p-4 rounded-2xl font-bold outline-none transition-all",
isEditing
? "bg-white border-canina-blue/30 focus:ring-2 focus:ring-canina-blue/20"
: "bg-medical-gray-50 border-medical-gray-100"
)}
/>
</div>
<div className="space-y-2">
<label htmlFor="email" className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block pr-4">ایمیل</label>
<input
type="email"
id="email"
name="email"
autoComplete="email"
required
readOnly={!isEditing}
value={isEditing ? profileForm.email : profile.email}
onChange={e => setProfileForm({ ...profileForm, email: e.target.value })}
className={cn(
"w-full border p-4 rounded-2xl font-bold outline-none transition-all text-left",
isEditing
? "bg-white border-canina-blue/30 focus:ring-2 focus:ring-canina-blue/20"
: "bg-medical-gray-50 border-medical-gray-100"
)}
dir="ltr"
/>
</div>
<div className="space-y-2">
<label htmlFor="mobile" className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block pr-4">شماره موبایل</label>
<input
type="tel"
id="mobile"
name="mobile"
autoComplete="tel"
required
readOnly={!isEditing}
disabled={!isEditing}
value={isEditing ? profileForm.mobile : toPersian(profile.mobile || "")}
onChange={e => setProfileForm({ ...profileForm, mobile: e.target.value.replace(/[^0-9]/g, '') })}
className={cn(
"w-full border p-4 rounded-2xl font-bold outline-none transition-all text-left",
isEditing
? "bg-white border-canina-blue/30 focus:ring-2 focus:ring-canina-blue/20"
: "bg-medical-gray-50 border-medical-gray-100 opacity-75 cursor-not-allowed"
)}
dir="ltr"
/>
</div>
</div>
<div className="flex gap-4 mt-8">
{isEditing ? (
<>
<button
type="submit"
disabled={isSavingProfile}
className="bg-canina-blue text-white px-10 py-4 rounded-2xl font-black hover:bg-indigo-700 transition-all flex items-center gap-2 disabled:opacity-50"
>
{isSavingProfile && <span className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" />}
ذخیره تغییرات
</button>
<button
type="button"
onClick={() => {
setProfileForm({
firstName: profile.firstName || "",
lastName: profile.lastName || "",
email: profile.email || "",
mobile: profile.mobile || ""
});
setIsEditing(false);
}}
className="bg-medical-gray-50 text-medical-gray-500 border border-medical-gray-200 px-10 py-4 rounded-2xl font-black hover:bg-medical-gray-100 transition-all"
>
انصراف
</button>
</>
) : (
<button
type="button"
onClick={() => setIsEditing(true)}
className="bg-medical-gray-900 text-white px-10 py-4 rounded-2xl font-black hover:bg-canina-blue transition-all"
>
ویرایش اطلاعات
</button>
)}
</div>
</form>
</div>
)}
{activeTab === "orders" && (
<div>
<div className="flex items-center justify-between mb-8">
<h3 className="text-2xl font-black text-medical-gray-900 italic">تاریخچه سفارشات</h3>
<div className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest border border-medical-gray-100 px-4 py-2 rounded-full bg-medical-gray-50">
تعداد کل: {toPersian((orders || []).length.toString())} مورد
</div>
</div>
{(orders || []).length === 0 ? (
<div className="text-center py-20">
<ShoppingBag className="w-16 h-16 text-medical-gray-200 mx-auto mb-4" />
<p className="text-medical-gray-400 font-bold">هنوز سفارشی ثبت نکردهاید.</p>
<button onClick={() => router.push('/shop')} className="mt-6 text-canina-blue font-black underline underline-offset-8">برو به فروشگاه</button>
</div>
) : (
<div className="space-y-4">
{isLoadingOrders ? (
[1, 2, 3].map(i => <OrderRowSkeleton key={i} />)
) : (
(orders || []).map(order => (
<motion.div
key={order.id}
whileHover={{ scale: 1.01, x: -5 }}
onClick={() => setSelectedOrder(order)}
className="p-6 border border-medical-gray-100 rounded-[2.5rem] hover:border-canina-blue transition-all group cursor-pointer bg-white overflow-hidden relative"
>
<div className="flex flex-wrap items-center justify-between gap-4">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-medical-gray-50 rounded-2xl flex items-center justify-center text-canina-blue group-hover:bg-canina-blue group-hover:text-white transition-all shadow-sm">
<Package className="w-6 h-6" />
</div>
<div>
<div className="text-sm font-black text-medical-gray-900 group-hover:text-canina-blue transition-colors italic">سفارش {toPersian(order.trackingNumber || order.id?.substring(0, 8))}</div>
<div className="text-[10px] font-bold text-medical-gray-400 flex items-center gap-1">
<Calendar className="w-3 h-3 opacity-30" />
{toPersian(new Date(order.date || (order as any).createdAt).toLocaleDateString("fa-IR"))} - ساعت {toPersian(new Date(order.date || (order as any).createdAt).toLocaleTimeString("fa-IR", { hour: '2-digit', minute: '2-digit' }))}
</div>
</div>
</div>
<div className="text-left">
<div className="text-lg font-black text-medical-gray-900 italic">{toPersian(order.total.toLocaleString())} <span className="text-xs">تومان</span></div>
<div className="flex items-center gap-2 justify-end mt-1">
{order.isRefill && (
<span className="text-[9px] font-black px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-600 border border-emerald-100">
تمدید خودکار ۵٪-
</span>
)}
<span className={`text-[9px] font-black px-2.5 py-0.5 rounded-full uppercase tracking-tighter ${order.status === 'delivered' ? 'bg-green-50 text-green-600' : order.status === 'shipped' ? 'bg-blue-50 text-blue-600' : 'bg-amber-50 text-amber-600'}`}>
{order.status === 'delivered' ? 'تحویل شده' : order.status === 'shipped' ? 'ارسال شده' : 'در حال پردازش'}
</span>
<ChevronRight className="w-4 h-4 text-medical-gray-300 -rotate-180" />
</div>
</div>
</div>
</motion.div>
))
)}
</div>
)}
</div>
)}
{activeTab === "addresses" && (
<div>
<div className="flex items-center justify-between mb-8">
<h3 className="text-2xl font-black text-medical-gray-900 italic">آدرسهای من</h3>
<button
onClick={handleAddClick}
className="px-6 py-3 bg-canina-blue text-white rounded-2xl font-black text-xs flex items-center gap-2 hover:bg-medical-gray-900 transition-all shadow-lg shadow-canina-blue/10"
>
<MapPin className="w-4 h-4" />
افزودن آدرس جدید
</button>
</div>
<div className="space-y-6">
{(profile?.addresses || []).length === 0 ? (
<div className="text-center py-20 border-2 border-dashed border-medical-gray-100 rounded-[3rem]">
<MapPin className="w-16 h-16 text-medical-gray-200 mx-auto mb-4" />
<p className="text-medical-gray-400 font-bold">هنوز آدرسی ثبت نکردهاید.</p>
</div>
) : (
(profile?.addresses || []).map((addr) => (
<motion.div
key={addr.id}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className={cn(
"p-8 bg-white border rounded-[2.5rem] relative group transition-all",
addr.isDefault ? "border-canina-blue shadow-xl shadow-canina-blue/5" : "border-medical-gray-100 hover:border-medical-gray-200"
)}
>
<div className="flex justify-between items-start mb-6">
<div className="flex items-center gap-4">
<div className={cn("w-12 h-12 rounded-2xl flex items-center justify-center transition-all", addr.isDefault ? "bg-canina-blue text-white shadow-lg" : "bg-medical-gray-50 text-canina-blue")}>
<MapPin className="w-6 h-6" />
</div>
<div>
<div className="flex items-center gap-3">
<h4 className="text-xl font-black text-medical-gray-900 italic">{addr.title}</h4>
{addr.isDefault && (
<span className="px-3 py-1 bg-green-50 text-green-600 text-[9px] font-black rounded-full uppercase tracking-widest">پیشفرض</span>
)}
</div>
<p className="text-xs font-bold text-medical-gray-400">تحویل گیرنده: {addr.receptorName}</p>
</div>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => handleEditClick(addr)}
className="w-10 h-10 flex items-center justify-center rounded-xl bg-medical-gray-50 text-medical-gray-400 hover:bg-canina-blue hover:text-white transition-all shadow-sm"
>
<Edit2 className="w-5 h-5" />
</button>
<button
onClick={() => handleDeleteClick(addr)}
className="w-10 h-10 flex items-center justify-center rounded-xl bg-medical-gray-50 text-medical-gray-400 hover:bg-red-500 hover:text-white transition-all shadow-sm"
>
<Trash2 className="w-5 h-5" />
</button>
</div>
</div>
<div className="bg-medical-gray-50/50 rounded-2xl p-6 mb-6">
<p className="text-sm font-black text-medical-gray-700 leading-relaxed text-right">{toPersian(addr.province)}، {toPersian(addr.city)}، {toPersian(addr.detail)}</p>
</div>
<div className="flex flex-wrap items-center gap-6">
<div className="flex items-center gap-2">
<Phone className="w-4 h-4 text-canina-blue/40" />
<span className="text-xs font-bold text-medical-gray-500" dir="ltr">{toPersian(addr.phone)}</span>
</div>
<div className="flex items-center gap-2">
<Hash className="w-4 h-4 text-canina-blue/40" />
<span className="text-xs font-bold text-medical-gray-500" dir="ltr">{toPersian(addr.zipCode)}</span>
</div>
{!addr.isDefault && (
<button
onClick={async () => {
try {
await setDefaultAddress(addr.id);
toast.success("آدرس پیش‌فرض با موفقیت تغییر کرد");
} catch (err) {
toast.error("خطا در تغییر آدرس پیش‌فرض");
}
}}
className="mr-auto text-[10px] font-black text-canina-blue hover:text-medical-gray-900 uppercase tracking-widest whitespace-nowrap"
>
انتخاب به عنوان پیشفرض
</button>
)}
{addr.isDefault && (
<div className="mr-auto flex items-center gap-2 text-green-600 text-[10px] font-black italic">
<CheckCircle2 className="w-4 h-4" />
آدرس اصلی ارسال
</div>
)}
</div>
</motion.div>
))
)}
</div>
</div>
)}
{activeTab === "wallet" && (
<div className="space-y-10">
<div className="flex items-center justify-between">
<h3 className="text-2xl font-black text-medical-gray-900 italic">مدیریت کیف پول</h3>
<div className="text-[10px] font-black text-green-600 bg-green-50 px-4 py-2 rounded-full uppercase tracking-widest border border-green-100 flex items-center gap-2">
<CheckCircle className="w-3 h-3" />
حساب تایید شده
</div>
</div>
{/* Main Balance Card */}
<div className="bg-gradient-to-br from-canina-blue to-blue-600 rounded-[2rem] sm:rounded-[3rem] p-6 sm:p-12 text-white shadow-2xl shadow-canina-blue/20 relative overflow-hidden group">
<div className="absolute top-0 right-0 p-6 sm:p-12 opacity-10 group-hover:scale-110 transition-transform duration-700 pointer-events-none">
<Wallet className="w-32 h-32 sm:w-48 sm:h-48" />
</div>
<div className="relative z-10 flex flex-col md:flex-row items-center justify-between gap-6 sm:gap-10">
<div className="text-center md:text-right w-full md:w-auto">
<div className="text-xs font-black uppercase tracking-[0.2em] text-white/70 mb-3 sm:mb-4 flex items-center gap-2 justify-center md:justify-start">
<div className="w-2 h-2 bg-white rounded-full animate-pulse" />
موجودی زنده و قابل استفاده
</div>
<div className="flex items-baseline gap-3 sm:gap-4 flex-row-reverse justify-center md:justify-start">
<div className="text-4xl sm:text-6xl font-black italic tracking-tight">{toPersian(profile.walletBalance.toLocaleString())}</div>
<span className="text-base sm:text-xl not-italic font-bold opacity-80 decoration-white/30 underline underline-offset-8">تومان</span>
</div>
</div>
<div className="flex flex-col sm:flex-row gap-3 sm:gap-4 w-full md:w-auto">
<div className="relative group/btn flex-1 md:flex-none">
<button
disabled
className="w-full md:w-40 h-12 sm:h-16 bg-white/10 backdrop-blur-md rounded-2xl font-black text-xs sm:text-sm flex items-center justify-center gap-2 border border-white/20 opacity-50 cursor-not-allowed"
>
<ArrowDownCircle className="w-4 h-4 sm:w-5 sm:h-5" />
برداشت وجه
</button>
<div className="absolute top-full right-0 mt-3 w-48 p-3 bg-medical-gray-900 text-white text-[10px] font-bold rounded-xl opacity-0 group-hover/btn:opacity-100 transition-all pointer-events-none z-20 text-center shadow-xl">
قابلیت برداشت وجه بهزودی فعال خواهد شد.
</div>
</div>
<button
onClick={() => setIsTopUpModalOpen(true)}
className="flex-1 md:w-40 h-12 sm:h-16 bg-white text-canina-blue rounded-2xl font-black text-xs sm:text-sm flex items-center justify-center gap-2 hover:bg-medical-gray-900 hover:text-white transition-all shadow-xl shadow-black/10 group/topup"
>
<ArrowUpCircle className="w-4 h-4 sm:w-5 sm:h-5 group-hover:-translate-y-1 transition-transform" />
شارژ آنی
</button>
</div>
</div>
</div>
{/* Transaction History */}
<div className="pt-10 border-t border-medical-gray-100">
<div className="flex items-center gap-4 mb-8">
<div className="w-10 h-10 bg-medical-gray-50 rounded-xl flex items-center justify-center text-medical-gray-400">
<Clock className="w-5 h-5" />
</div>
<h4 className="text-lg font-black text-medical-gray-900 italic">تاریخچه تراکنشها</h4>
</div>
<div className="space-y-4">
{(profile?.transactions || []).length === 0 ? (
<div className="text-center py-20 bg-medical-gray-50 rounded-[2.5rem] border border-dashed border-medical-gray-200">
<Info className="w-12 h-12 text-medical-gray-200 mx-auto mb-4" />
<p className="text-medical-gray-400 font-bold">تراکنشی یافت نشد.</p>
</div>
) : (
(profile?.transactions || []).map((trx) => (
<div key={trx.id} className="p-4 sm:p-6 bg-white border border-medical-gray-100 rounded-[1.5rem] sm:rounded-[2rem] flex flex-col sm:flex-row sm:items-center justify-between gap-4 sm:gap-6 hover:shadow-lg hover:border-canina-blue/10 transition-all group">
<div className="flex items-center gap-3 sm:gap-4">
<div className={cn(
"w-10 h-10 sm:w-12 sm:h-12 rounded-xl sm:rounded-2xl flex items-center justify-center transition-colors flex-shrink-0",
trx.type === 'top_up' ? "bg-green-50 text-green-500 group-hover:bg-green-500 group-hover:text-white" : "bg-red-50 text-red-500 group-hover:bg-red-500 group-hover:text-white"
)}>
{trx.type === 'top_up' ? <ArrowUpCircle className="w-5 h-5 sm:w-6 sm:h-6" /> : <ShoppingCart className="w-5 h-5 sm:w-6 sm:h-6" />}
</div>
<div className="min-w-0">
<div className="text-xs sm:text-sm font-black text-medical-gray-900 truncate">{trx.type === 'top_up' ? "افزایش موجودی (شارژ)" : "پرداخت سفارش"}</div>
<div className="text-[10px] font-bold text-medical-gray-400 flex flex-wrap items-center gap-1 sm:gap-2 mt-0.5">
<span className="truncate">کد: {trx.id}</span>
<span className="w-1 h-1 bg-medical-gray-200 rounded-full hidden sm:inline-block" />
<span>{toPersian(new Date(trx.date).toLocaleDateString("fa-IR"))}</span>
</div>
</div>
</div>
<div className="text-right sm:text-left flex sm:flex-col justify-between items-center sm:items-end border-t sm:border-t-0 pt-2 sm:pt-0 border-medical-gray-50">
<div className={cn(
"text-base sm:text-lg font-black italic",
trx.type === 'top_up' ? "text-green-600" : "text-red-500"
)}>
{trx.type === 'top_up' ? "+" : ""}{toPersian(trx.amount.toLocaleString())} <span className="text-xs not-italic">تومان</span>
</div>
<div className="text-[9px] font-black uppercase text-green-500 tracking-widest sm:mt-1">
تایید شده
</div>
</div>
</div>
))
)}
</div>
</div>
</div>
)}
{activeTab === "tickets" && (
<div>
<div className="flex items-center justify-between mb-8">
<h3 className="text-2xl font-black text-medical-gray-900 italic">پشتیبانی و مشاوره آنلاین دامپزشک</h3>
<button
onClick={() => toast.info("فرم ارسال تیکت جدید فعال شد")}
className="px-4 py-2 bg-canina-blue text-white rounded-xl text-xs font-black flex items-center gap-1.5 hover:bg-canina-dark transition-all"
>
<Send className="w-3.5 h-3.5" />
ثبت تیکت جدید
</button>
</div>
<div className="space-y-4">
<div className="p-6 bg-medical-gray-50 border border-medical-gray-200 rounded-[2rem] flex flex-col md:flex-row items-start md:items-center justify-between gap-4">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-canina-blue/10 text-canina-blue rounded-2xl flex items-center justify-center">
<Stethoscope className="w-6 h-6" />
</div>
<div>
<h4 className="font-black text-medical-gray-900 text-sm">مشاوره دوز مکمل کانینوکال برای سگ ژرمن</h4>
<p className="text-xs text-medical-gray-400 mt-1">شناسه تیکت: TK-۸۴۹۲ پاسخ داده شده توسط دکتر صادقی</p>
</div>
</div>
<span className="px-3 py-1 bg-green-50 text-green-700 text-xs font-black rounded-full border border-green-200">
پاسخ داده شد
</span>
</div>
<div className="p-6 bg-medical-gray-50 border border-medical-gray-200 rounded-[2rem] flex flex-col md:flex-row items-start md:items-center justify-between gap-4 opacity-75">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-amber-50 text-amber-600 rounded-2xl flex items-center justify-center">
<FileText className="w-6 h-6" />
</div>
<div>
<h4 className="font-black text-medical-gray-900 text-sm">استعلام اصالت نسخه پزشکی و سفارش فوری</h4>
<p className="text-xs text-medical-gray-400 mt-1">شناسه تیکت: TK-۸۴۱۰ در حال بررسی توسط کارشناس دارویی</p>
</div>
</div>
<span className="px-3 py-1 bg-amber-50 text-amber-700 text-xs font-black rounded-full border border-amber-200">
در حال بررسی
</span>
</div>
</div>
</div>
)}
</motion.div>
</div>
{/* Sidebar Widgets (Wallet & Charity) */}
<div className="lg:col-span-4 space-y-4 sm:space-y-6 min-w-0 order-2 lg:order-2">
<div className="bg-medical-gray-900 rounded-[1.5rem] sm:rounded-[3rem] p-5 sm:p-8 text-white relative overflow-hidden shadow-2xl">
<div className="absolute top-0 left-0 p-6 opacity-20 pointer-events-none">
<Wallet className="w-12 h-12 text-canina-blue" />
</div>
<div className="relative z-10">
<div className="text-[10px] font-black uppercase tracking-widest text-white/70 mb-2">موجودی کیف پول</div>
<div className="flex items-baseline gap-2 flex-row-reverse justify-end">
<div className="text-2xl sm:text-4xl font-black italic">{toPersian((profile.walletBalance ?? 0).toLocaleString())}</div>
<span className="text-xs sm:text-sm not-italic font-bold text-white/80">تومان</span>
</div>
<button
onClick={() => { setActiveTab("wallet"); setIsTopUpModalOpen(true); }}
disabled={isTopUpModalOpen}
className="mt-5 sm:mt-8 bg-canina-blue text-white w-full py-3.5 sm:py-4 px-4 rounded-2xl font-black hover:bg-white hover:text-canina-blue transition-all shadow-lg shadow-black/20 flex items-center justify-center gap-2 text-xs sm:text-sm border border-canina-blue"
>
<ArrowUpCircle className="w-4 h-4 sm:w-5 sm:h-5 flex-shrink-0" />
<span>شارژ کیف پول</span>
</button>
</div>
</div>
<div className="bg-pink-500 rounded-[1.5rem] sm:rounded-[3rem] p-5 sm:p-8 text-white relative overflow-hidden shadow-2xl shadow-pink-200">
<div className="absolute -top-4 -right-4 opacity-10 pointer-events-none">
<Heart className="w-32 sm:w-40 h-32 sm:h-40 fill-white" />
</div>
<div className="relative z-10">
<div className="flex items-center gap-2 sm:gap-3 mb-4 sm:mb-6">
<Heart className="w-4 h-4 sm:w-5 sm:h-5 fill-white flex-shrink-0" />
<h4 className="text-xs sm:text-sm font-black italic tracking-widest">ردپای مهربانی</h4>
</div>
<div className="space-y-4 sm:space-y-6">
<div>
<p className="text-[10px] font-bold text-white/70 mb-1">مجموع کمکهای اهدایی</p>
<div className="flex items-baseline gap-2 flex-row-reverse justify-end">
<span className="text-xl sm:text-3xl font-black italic">
{toPersian((Math.max(profile.charityDonationTotal || 0, orders.reduce((sum, o) => sum + Number(o.charityDonation || 0), 0))).toLocaleString())}
</span>
<span className="text-xs font-bold opacity-60">تومان</span>
</div>
</div>
<div className="p-3 sm:p-4 bg-white/10 rounded-xl sm:rounded-2xl border border-white/20 backdrop-blur-sm">
<div className="flex items-start gap-2.5 sm:gap-3">
<div className="w-6 h-6 sm:w-8 sm:h-8 bg-white/20 rounded-lg sm:rounded-xl flex items-center justify-center flex-shrink-0 mt-0.5">
<Sparkles className="w-3 h-3 sm:w-4 sm:h-4 text-white" />
</div>
<p className="text-[10px] sm:text-xs font-black leading-relaxed">
همکاری شما باعث تامین هزینه <span className="text-xs sm:text-sm text-yellow-300 mx-1">{toPersian(Math.floor((profile.charityDonationTotal || 0) / 15000).toString())} وعده غذا</span> برای حیوانات بیپناه شده است.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<OrderDetailsModal
isOpen={!!selectedOrder}
onClose={() => setSelectedOrder(null)}
order={selectedOrder}
/>
<AddressModal
isOpen={isAddressModalOpen}
onClose={() => setIsAddressModalOpen(false)}
onSave={handleSaveAddress}
editingAddress={editingAddress}
/>
<DeleteConfirmModal
isOpen={isDeleteModalOpen}
onClose={() => setIsDeleteModalOpen(false)}
onConfirm={handleConfirmDelete}
title="حذف آدرس"
message={`آیا از حذف آدرس "${addressToDelete?.title}" اطمینان دارید؟ این عمل غیرقابل بازگشت است.`}
/>
<TopUpModal
isOpen={isTopUpModalOpen}
onClose={() => setIsTopUpModalOpen(false)}
onConfirm={topUpWallet}
/>
</div>
);
}