197 lines
7.5 KiB
TypeScript
197 lines
7.5 KiB
TypeScript
import Link from "next/link";
|
|
import { Minus, Plus, Heart, ShoppingCart, Store } from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Card } from "@/components/ui/card";
|
|
|
|
interface ProductPurchaseCardProps {
|
|
price: string;
|
|
oldPrice?: string;
|
|
isInCart: boolean;
|
|
localQuantity: number;
|
|
availableStock: number;
|
|
isSyncing: boolean;
|
|
syncError: boolean;
|
|
isFavorite: boolean;
|
|
productStock: number;
|
|
channelName?: string;
|
|
onAddToCart: () => void;
|
|
onQuantityIncrease: () => void;
|
|
onQuantityDecrease: () => void;
|
|
onToggleFavorite: () => void;
|
|
t: (key: string) => string;
|
|
}
|
|
|
|
export function ProductPurchaseCard({
|
|
price,
|
|
oldPrice,
|
|
isInCart,
|
|
localQuantity,
|
|
availableStock,
|
|
isSyncing,
|
|
syncError,
|
|
isFavorite,
|
|
productStock,
|
|
channelName,
|
|
onAddToCart,
|
|
onQuantityIncrease,
|
|
onQuantityDecrease,
|
|
onToggleFavorite,
|
|
t,
|
|
}: ProductPurchaseCardProps) {
|
|
const isOutOfStock = productStock === 0;
|
|
|
|
return (
|
|
<div className="lg:w-[420px] space-y-4">
|
|
<Card className="p-3 md:p-6 rounded-lg border border-gray-200 shadow-lg hover:shadow-xl transition-shadow duration-300">
|
|
{/* Price Section */}
|
|
<div className="flex justify-between items-baseline mb-3 pb-4 border-b border-gray-100 ">
|
|
<span className="text-lg font-medium text-gray-600">
|
|
{t("price")}:
|
|
</span>
|
|
<div className="flex flex-col items-end">
|
|
<span className="text-4xl font-bold text-gray-900 tracking-tight">
|
|
{price}{" "}
|
|
<span className="text-2xl font-semibold text-gray-500">TMT</span>
|
|
</span>
|
|
{oldPrice && parseFloat(oldPrice) > 0 && (
|
|
<span className="text-lg text-gray-400 line-through mt-1">
|
|
{oldPrice} TMT
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Action Buttons Section */}
|
|
<div className="space-y-3">
|
|
{isInCart ? (
|
|
<>
|
|
{/* Go to Cart Button */}
|
|
<Link href="/cart">
|
|
<Button
|
|
size="lg"
|
|
className="w-full h-12 rounded-[10px] cursor-pointer text-lg font-bold bg-gradient-to-r from-emerald-600 to-emerald-500 hover:from-emerald-700 hover:to-emerald-600 shadow-md hover:shadow-lg transition-all duration-300"
|
|
>
|
|
<ShoppingCart className="mr-2 h-5 w-5" />
|
|
{t("go_to_cart")}
|
|
</Button>
|
|
</Link>
|
|
|
|
{/* Quantity Controls */}
|
|
<div className="flex items-center gap-3 pt-2">
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={onQuantityDecrease}
|
|
disabled={isSyncing}
|
|
className={`rounded-[10px] h-12 w-12 border-2 border-gray-200 hover:border-gray-900 hover:bg-gray-50 transition-all duration-200 disabled:opacity-30 disabled:cursor-not-allowed ${
|
|
isSyncing ? "opacity-50" : ""
|
|
}`}
|
|
>
|
|
<Minus className="h-5 w-5 text-gray-700" />
|
|
</Button>
|
|
|
|
<div className="flex-1 text-center font-semibold text-2xl border-2 border-gray-200 rounded-[10px] h-12 flex items-center justify-center bg-white relative">
|
|
{isSyncing ? (
|
|
<div className="absolute inset-0 bg-white/80 rounded-2xl flex items-center justify-center">
|
|
<div className="w-5 h-5 border-2 border-gray-300 border-t-gray-900 rounded-full animate-spin" />
|
|
</div>
|
|
) : null}
|
|
<span className={isSyncing ? "opacity-30" : ""}>
|
|
{localQuantity}
|
|
</span>
|
|
{syncError && (
|
|
<span
|
|
className="absolute -top-1 -right-1 h-3 w-3 bg-red-500 rounded-full border-2 border-white shadow-sm"
|
|
title="Sync error"
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={onQuantityIncrease}
|
|
disabled={isSyncing}
|
|
className={`rounded-[10px] h-12 w-12 border-2 border-gray-900 bg-gray-900 hover:bg-gray-800 transition-all duration-200 ${
|
|
localQuantity >= availableStock
|
|
? "opacity-60 border-gray-200"
|
|
: ""
|
|
} ${isSyncing ? "opacity-50" : ""}`}
|
|
>
|
|
<Plus className="h-5 w-5 text-white" />
|
|
</Button>
|
|
|
|
{/* Favorite Button - In Cart */}
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={onToggleFavorite}
|
|
className={`rounded-[10px] h-12 w-12 transition-all duration-200 border-2 cursor-pointer ${
|
|
isFavorite
|
|
? "bg-rose-50 border-rose-200 hover:bg-rose-100 hover:border-rose-300"
|
|
: "border-gray-200 hover:border-gray-900 hover:bg-gray-50"
|
|
}`}
|
|
>
|
|
<Heart
|
|
className={`h-6 w-6 transition-all duration-200 ${
|
|
isFavorite
|
|
? "fill-rose-500 text-rose-500 scale-110"
|
|
: "text-gray-700 hover:text-rose-500"
|
|
}`}
|
|
/>
|
|
</Button>
|
|
</div>
|
|
</>
|
|
) : (
|
|
<div className="flex items-center gap-3">
|
|
{/* Add to Cart Button */}
|
|
<Button
|
|
size="lg"
|
|
onClick={onAddToCart}
|
|
disabled={isSyncing || isOutOfStock}
|
|
className={`flex-1 h-12 rounded-[10px] text-lg font-bold shadow-md hover:shadow-lg transition-all duration-300 cursor-pointer ${
|
|
isOutOfStock
|
|
? "bg-gray-300 text-gray-600 cursor-not-allowed"
|
|
: "bg-gradient-to-r from-gray-900 to-gray-800 hover:from-gray-800 hover:to-gray-700"
|
|
}`}
|
|
>
|
|
{isSyncing ? (
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
|
<span>{t("adding")}</span>
|
|
</div>
|
|
) : (
|
|
<>
|
|
<ShoppingCart className="mr-2 h-5 w-5" />
|
|
{isOutOfStock ? t("out_of_stock") : t("add_to_cart")}
|
|
</>
|
|
)}
|
|
</Button>
|
|
|
|
{/* Favorite Button - Not in Cart */}
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={onToggleFavorite}
|
|
className={`rounded-[10px] h-12 w-12 transition-all duration-200 border-2 cursor-pointer ${
|
|
isFavorite
|
|
? "bg-rose-50 border-rose-200 hover:bg-rose-100 hover:border-rose-300"
|
|
: "border-gray-200 hover:border-gray-900 hover:bg-gray-50"
|
|
}`}
|
|
>
|
|
<Heart
|
|
className={`h-6 w-6 transition-all duration-200 ${
|
|
isFavorite
|
|
? "fill-rose-500 text-rose-500 scale-110"
|
|
: "text-gray-700 hover:text-rose-500"
|
|
}`}
|
|
/>
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|