feat: interactive pages migrated to Next.js (Dashboard, Checkout, Profile, Wiki)

This commit is contained in:
پارسا آقایی 2026-06-12 01:10:52 +03:30
parent 3de0408e6f
commit 976dfcd610
8 changed files with 49 additions and 20 deletions

View File

@ -0,0 +1,5 @@
import CheckoutPage from "../../components/CheckoutPage";
export default function Checkout() {
return <CheckoutPage />;
}

View File

@ -0,0 +1,5 @@
import UserDashboard from "../../components/UserDashboard";
export default function DashboardPage() {
return <UserDashboard />;
}

View File

@ -0,0 +1,5 @@
import PetProfile from "../../components/PetProfile";
export default function ProfilePage() {
return <PetProfile />;
}

View File

@ -0,0 +1,5 @@
import IngredientWiki from "../../components/IngredientWiki";
export default function WikiPage() {
return <IngredientWiki />;
}

View File

@ -23,8 +23,10 @@ import { useUserStore } from "../store/userStore";
import { Product } from "../data/products";
import { productService } from "../services/productService";
import { toast } from "sonner";
import { useRouter } from 'next/navigation';
export default function CheckoutPage({ onBack, onComplete }: { onBack: () => void; onComplete: (orderId: string) => void }) {
export default function CheckoutPage() {
const router = useRouter();
const { items, getTotal, getSubtotal, getDiscount, isSubscribed, charityDonation, setCharityDonation, addOrder, clearCart } = useCartStore();
const { getActivePet, updatePet } = usePetStore();
const { profile, updateProfile } = useUserStore();
@ -94,8 +96,8 @@ export default function CheckoutPage({ onBack, onComplete }: { onBack: () => voi
}
clearCart();
onComplete(orderId);
toast.success("سفارش شما با موفقیت ثبت شد و به پرونده سلامت همدمتان اضافه شد!");
router.push('/dashboard');
} catch (err: any) {
toast.error(err.message || "خطا در ثبت سفارش. لطفاً مجدداً تلاش کنید.");
} finally {
@ -111,7 +113,7 @@ export default function CheckoutPage({ onBack, onComplete }: { onBack: () => voi
<ShieldCheck className="w-12 h-12" />
</div>
<h2 className="text-2xl font-black text-medical-gray-900 italic">سبد خرید شما خالی است</h2>
<button onClick={onBack} className="text-canina-blue font-black underline underline-offset-8">بازگشت به فروشگاه</button>
<button onClick={() => router.push('/shop')} className="text-canina-blue font-black underline underline-offset-8">بازگشت به فروشگاه</button>
</div>
</div>
);
@ -124,7 +126,7 @@ export default function CheckoutPage({ onBack, onComplete }: { onBack: () => voi
{/* Mobile Navigation & Breadcrumbs */}
<div className="lg:hidden mb-10 space-y-4">
<button
onClick={onBack}
onClick={() => router.back()}
className="flex items-center gap-2 text-medical-gray-500 font-bold hover:text-canina-blue transition-colors"
>
<ChevronRight className="w-5 h-5" />
@ -132,7 +134,7 @@ export default function CheckoutPage({ onBack, onComplete }: { onBack: () => voi
</button>
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest overflow-x-auto whitespace-nowrap pb-2">
<span className="cursor-pointer hover:text-canina-blue" onClick={onBack}>سبد خرید</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/shop')}>سبد خرید</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canina-blue">نهاییسازی سفارش</span>
</div>
@ -140,7 +142,7 @@ export default function CheckoutPage({ onBack, onComplete }: { onBack: () => voi
{/* Desktop Breadcrumbs (Hidden on Mobile) */}
<div className="hidden lg:flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-10">
<span className="cursor-pointer hover:text-canina-blue" onClick={onBack}>خانه</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canina-blue">درگاه پرداخت امن و نهاییسازی</span>
</div>

View File

@ -6,7 +6,10 @@ import { FlaskConical, CheckCircle2, ChevronRight, ChevronLeft, Beaker } from "l
import { useSettingsStore } from "../store/settingsStore";
import { productService } from "../services/productService";
export default function IngredientWiki({ onProductClick, onBack }: { onProductClick: (p: Product) => void, onBack?: () => void }) {
import { useRouter } from 'next/navigation';
export default function IngredientWiki() {
const router = useRouter();
const texts = useSettingsStore(state => state.texts);
const [products, setProducts] = useState<Product[]>([]);
@ -33,7 +36,7 @@ export default function IngredientWiki({ onProductClick, onBack }: { onProductCl
{/* Mobile Navigation & Breadcrumbs */}
<div className="lg:hidden mb-12 space-y-4">
<button
onClick={onBack}
onClick={() => router.back()}
className="flex items-center gap-2 text-medical-gray-500 font-bold hover:text-canina-blue transition-colors"
>
<ChevronRight className="w-5 h-5" />
@ -41,7 +44,7 @@ export default function IngredientWiki({ onProductClick, onBack }: { onProductCl
</button>
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest overflow-x-auto whitespace-nowrap pb-2">
<span className="cursor-pointer hover:text-canina-blue" onClick={onBack}>کانینا</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>کانینا</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canina-blue">دانشنامه علمی</span>
</div>
@ -49,7 +52,7 @@ export default function IngredientWiki({ onProductClick, onBack }: { onProductCl
{/* Desktop Breadcrumbs */}
<div className="hidden lg:flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-12">
<span className="cursor-pointer hover:text-canina-blue" onClick={onBack}>خانه</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canina-blue">دانشنامه مواد نایاب و ارگانیک</span>
</div>
@ -122,7 +125,7 @@ export default function IngredientWiki({ onProductClick, onBack }: { onProductCl
{hasIngredient.length > 0 ? hasIngredient.map(p => (
<div
key={p.id}
onClick={() => onProductClick(p)}
onClick={() => router.push(`/shop/${p.id}`)}
className="bg-white rounded-[2.5rem] p-6 shadow-xl hover:scale-105 transition-transform cursor-pointer group"
>
<img src={p.image} alt={p.name} className="w-24 h-24 object-contain mx-auto mb-4" referrerPolicy="no-referrer" />

View File

@ -35,12 +35,13 @@ import SafeImage from "./SafeImage";
import { toast } from "sonner";
import { toPersian, cn } from "../lib/utils";
export default function PetProfile({ onProductClick, onBack, initialView, advisorNeed }: {
onProductClick: (p: Product) => void,
onBack?: () => void,
import { useRouter } from 'next/navigation';
export default function PetProfile({ initialView, advisorNeed }: {
initialView?: "index" | "detail" | "add" | "edit",
advisorNeed?: string | null
}) {
const router = useRouter();
const { pets, activePetId, addPet, removePet, setActivePet, getActivePet, updatePet, addReminder, toggleReminder, addHealthLog } = usePetStore();
const { orders } = useCartStore();
const activePet = getActivePet();
@ -553,7 +554,7 @@ export default function PetProfile({ onProductClick, onBack, initialView, adviso
onClick={() => {
if (view === "edit") setView("detail");
else if (pets.length > 0) setView("index");
else onBack?.();
else router.back();
}}
className="absolute top-8 left-8 text-medical-gray-400 hover:text-canina-blue transition-colors text-[10px] font-black uppercase tracking-widest"
>
@ -757,7 +758,7 @@ export default function PetProfile({ onProductClick, onBack, initialView, adviso
{isLow && (
<button
onClick={() => onProductClick(product)}
onClick={() => router.push(`/shop/${product.id}`)}
className="w-full py-2 bg-red-500 text-white rounded-xl text-[10px] font-black uppercase tracking-widest hover:bg-red-600 transition-all flex items-center justify-center gap-2"
>
<Package className="w-3.5 h-3.5" />

View File

@ -12,7 +12,10 @@ import AddressModal from "./AddressModal";
import DeleteConfirmModal from "./DeleteConfirmModal";
import TopUpModal from "./TopUpModal";
export default function UserDashboard({ onBack, onNavigate }: { onBack: () => void, onNavigate: (v: any) => void }) {
import { useRouter } from 'next/navigation';
export default function UserDashboard() {
const router = useRouter();
const { profile, logout, addAddress, updateAddress, deleteAddress, setDefaultAddress, topUpWallet } = useUserStore();
const { orders } = useCartStore();
const [activeTab, setActiveTab] = React.useState<"profile" | "orders" | "wallet" | "addresses">("profile");
@ -85,7 +88,7 @@ export default function UserDashboard({ onBack, onNavigate }: { onBack: () => vo
const handleLogout = () => {
logout();
onBack();
router.push('/');
};
const handleSaveAddress = async (addr: Address) => {
@ -140,7 +143,7 @@ export default function UserDashboard({ onBack, onNavigate }: { onBack: () => vo
<div className="max-w-6xl mx-auto">
{/* Breadcrumb */}
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-10">
<span className="cursor-pointer hover:text-canina-blue" onClick={onBack}>خانه</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronRight className="w-2.5 h-2.5" />
<span className="text-canina-blue">پنل کاربری</span>
</div>
@ -380,7 +383,7 @@ export default function UserDashboard({ onBack, onNavigate }: { onBack: () => vo
<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={() => onNavigate("shop")} className="mt-6 text-canina-blue font-black underline underline-offset-8">برو به فروشگاه</button>
<button onClick={() => router.push('/shop')} className="mt-6 text-canina-blue font-black underline underline-offset-8">برو به فروشگاه</button>
</div>
) : (
<div className="space-y-4">