Stripe Payment

This commit is contained in:
augmentedpotato
2026-04-09 22:27:03 -06:00
parent a7ba0fb4b4
commit 1010d57b79
26 changed files with 2022 additions and 33 deletions

View File

@@ -1,26 +1,97 @@
"use client";
import Link from "next/link";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { useAuth } from "@/context/AuthContext";
import { useCart } from "@/context/CartContext";
export default function ProductCard({ prodId, prodName, categoryName, prodPrice, imageUrl }) {
const { user } = useAuth();
const { addItem, selectedStoreId } = useCart();
const router = useRouter();
const [quantity, setQuantity] = useState(1);
const [adding, setAdding] = useState(false);
const [feedback, setFeedback] = useState(null);
async function handleAddToCart(e) {
e.preventDefault();
if (!user) {
router.push("/login");
return;
}
if (!selectedStoreId) {
setFeedback("Please select a store first");
setTimeout(() => setFeedback(null), 2500);
return;
}
setAdding(true);
setFeedback(null);
try {
await addItem(prodId, quantity);
setFeedback("Added!");
setTimeout(() => setFeedback(null), 1500);
} catch (err) {
setFeedback(err.message || "Failed to add");
setTimeout(() => setFeedback(null), 2500);
} finally {
setAdding(false);
}
}
return (
<Link href={`/products/${prodId}`} className="pet-card">
<div className="pet-card-image-wrapper">
<img
src={imageUrl || "/images/pet-placeholder.png"}
alt={prodName}
className="pet-card-image"
onError={(e) => {
e.currentTarget.onerror = null;
e.currentTarget.src = "/images/pet-placeholder.png";
}}
/>
<div className="pet-card product-card-wrapper">
<Link href={`/products/${prodId}`} className="product-card-link">
<div className="pet-card-image-wrapper">
<img
src={imageUrl || "/images/pet-placeholder.png"}
alt={prodName}
className="pet-card-image"
onError={(e) => {
e.currentTarget.onerror = null;
e.currentTarget.src = "/images/pet-placeholder.png";
}}
/>
</div>
<div className="pet-card-body">
<h3 className="pet-card-name">{prodName}</h3>
<p className="pet-card-species">{categoryName}</p>
{prodPrice != null && (
<span className="product-card-price">${parseFloat(prodPrice).toFixed(2)}</span>
)}
</div>
</Link>
<div className="product-card-actions">
<div className="product-card-qty-row">
<button
className="product-card-qty-btn"
type="button"
onClick={() => setQuantity((q) => Math.max(1, q - 1))}
disabled={adding}
>
</button>
<span className="product-card-qty-val">{quantity}</span>
<button
className="product-card-qty-btn"
type="button"
onClick={() => setQuantity((q) => q + 1)}
disabled={adding}
>
+
</button>
</div>
<button
className="product-card-add-btn"
type="button"
onClick={handleAddToCart}
disabled={adding}
>
{adding ? "Adding…" : "Add to Cart"}
</button>
{feedback && <p className="product-card-feedback">{feedback}</p>}
</div>
<div className="pet-card-body">
<h3 className="pet-card-name">{prodName}</h3>
<p className="pet-card-species">{categoryName}</p>
{prodPrice != null && (
<span className="product-card-price">${parseFloat(prodPrice).toFixed(2)}</span>
)}
</div>
</Link>
</div>
);
}