Files
group-2-threaded-project-pe…/web/components/ProductProfile.js
2026-04-20 22:01:15 -06:00

118 lines
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
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 { useState } from "react";
import { useAuth } from "@/context/AuthContext";
import { useCart } from "@/context/CartContext";
const fieldRowCls = "flex items-center px-5 py-[0.85rem] border-b border-[#eee] last:border-b-0";
const fieldLabelCls = "w-[140px] text-[0.9rem] font-semibold text-[#888] uppercase tracking-[0.04em] shrink-0";
const fieldValueCls = "text-base text-[#333]";
const qtyBtnCls = "w-7 h-7 border border-[#ddd] rounded-md bg-white text-base cursor-pointer flex items-center justify-center transition-colors hover:border-[#e68672] disabled:opacity-50";
//Full detail view for a single product, shown on the product detail page
export default function ProductProfile({ prodId, prodName, categoryName, prodDesc, prodPrice, imageUrl }) {
const { user } = useAuth();
const { addItem, selectedStoreId } = useCart();
const [quantity, setQuantity] = useState(1);
const [adding, setAdding] = useState(false);
const [feedback, setFeedback] = useState(null);
//Increments or decrements quantity, minimum of 1
function changeQty(delta) { setQuantity((q) => Math.max(1, q + delta)); }
//Adds the chosen quantity to the cart and shows a success or error message
async function handleAddToCart() {
setAdding(true);
setFeedback(null);
try {
await addItem(prodId, quantity);
setFeedback({ type: "success", message: `${quantity} × ${prodName} added to cart!` });
setQuantity(1);
setTimeout(() => setFeedback(null), 1000);
} catch (err) {
setFeedback({ type: "error", message: err.message ?? "Failed to add to cart." });
} finally {
setAdding(false);
}
}
return (
<div className="flex gap-12 bg-white rounded-2xl shadow-[0_6px_24px_rgba(0,0,0,0.1)] overflow-hidden max-[768px]:flex-col max-[768px]:gap-0">
<div className="shrink-0 w-[280px] bg-[#fff8ee] flex items-center justify-center max-[768px]:w-full max-[768px]:h-[200px]">
<img
src={imageUrl || "/images/pet-placeholder.png"}
alt={prodName}
className="w-full h-full object-cover"
onError={(e) => {
e.currentTarget.onerror = null;
e.currentTarget.src = "/images/pet-placeholder.png";
}}
/>
</div>
<div className="flex-1 py-10 pr-10 flex flex-col gap-6 max-[768px]:p-7">
<div className="flex items-center gap-4 flex-wrap">
<h1 className="text-[2.2rem] font-bold text-[#222] m-0">{prodName}</h1>
</div>
<div className="flex flex-col border border-[#eee] rounded-[10px] overflow-hidden">
<div className={fieldRowCls}>
<span className={fieldLabelCls}>Category</span>
<span className={fieldValueCls}>{categoryName ?? "-"}</span>
</div>
<div className={fieldRowCls}>
<span className={fieldLabelCls}>Price</span>
<span className={`${fieldValueCls} font-bold text-[#1a7a3c] text-[1.1rem]`}>
{prodPrice != null ? `$${parseFloat(prodPrice).toFixed(2)}` : "-"}
</span>
</div>
<div className={fieldRowCls}>
<span className={fieldLabelCls}>Description</span>
<span className={fieldValueCls}>{prodDesc ?? "-"}</span>
</div>
</div>
<div className="bg-[#fff8ee] rounded-xl p-5">
{!user ? (
<p className="text-[0.95rem] text-[#555] m-0">
<a href="/login" className="text-[#e68672] font-semibold no-underline hover:underline">Log in</a> to purchase this item.
</p>
) : !selectedStoreId ? (
<p className="text-[0.95rem] text-[#555] m-0">
Select a store from the navigation bar to add items to your cart.
</p>
) : (
<>
<div className="flex items-center gap-4 mb-4">
<span className="text-[0.95rem] font-semibold text-[#555]">Quantity</span>
<div className="flex items-center gap-2">
<button className={qtyBtnCls} onClick={() => changeQty(-1)} disabled={quantity <= 1 || adding} aria-label="Decrease quantity"></button>
<span className="min-w-7 text-center font-semibold">{quantity}</span>
<button className={qtyBtnCls} onClick={() => changeQty(1)} disabled={adding} aria-label="Increase quantity">+</button>
</div>
</div>
<button
className="w-full py-[0.85rem] border-none rounded-[10px] text-base font-bold cursor-pointer transition-all active:scale-[0.98] disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center gap-2"
style={feedback?.type === "success" ? { background: "#2ecc71", color: "white", boxShadow: "0 0 16px 4px rgba(46,204,113,0.6)" } : { background: "#e68672", color: "#2f2f2f" }}
onClick={handleAddToCart}
disabled={adding}
>
<img src="/bootstrap/cart-plus-fill.svg" alt="" className="w-5 h-5" style={{ filter: "brightness(0) invert(0.2)" }} />
{adding ? "Adding…" : "Add to Cart"}
</button>
{feedback?.type === "error" && (
<p className="mt-3 text-[0.9rem] rounded-lg px-4 py-[0.6rem] m-0 bg-[#fff0f0] border border-[#f5c6c6] text-[#c0392b]">
{feedback.message}
</p>
)}
</>
)}
</div>
</div>
</div>
);
}