remove item from shop after purchase

This commit is contained in:
Emily Neighbour 2025-05-30 14:05:56 +01:00
parent 183a53b178
commit 17672177c6

View File

@ -1,48 +1,50 @@
"use client"; "use client";
import Image from "next/image"; import Image from "next/image";
import { Dispatch, SetStateAction, useCallback, useState, useEffect } from "react"; import { Dispatch, SetStateAction, useCallback, useEffect, useState } from "react";
import BottomFooter from "@components/BottomFooter";
import { ExtendedArtefact } from "@appTypes/ApiTypes"; import { ExtendedArtefact } from "@appTypes/ApiTypes";
import { Currency } from "@appTypes/StoreModel"; import { Currency } from "@appTypes/StoreModel";
import BottomFooter from "@components/BottomFooter";
import { useStoreState } from "@hooks/store"; import { useStoreState } from "@hooks/store";
// todo hide from shop after purchase // todo hide from shop after purchase
export default function Shop() { export default function Shop() {
const [artefacts, setArtefacts] = useState<ExtendedArtefact[]>([]); const [artefacts, setArtefacts] = useState<ExtendedArtefact[]>([]);
const [loading, setLoading] = useState(true); const [hiddenArtefactIds, setHiddenArtefactIds] = useState<number[]>([]);
const [loading, setLoading] = useState(true);
const user = useStoreState((state) => state.user);
// 3. Fetch from your API route and map data to fit your existing fields // 3. Fetch from your API route and map data to fit your existing fields
useEffect(() => { useEffect(() => {
async function fetchArtefacts() { async function fetchArtefacts() {
setLoading(true); setLoading(true);
try { try {
// todo only show only non-required artefacts // todo only show only non-required artefacts
const res = await fetch("/api/artefacts"); const res = await fetch("/api/artefacts");
const data = await res.json(); const data = await res.json();
const transformed = data.artefact.map((a: any) => ({ const transformed = data.artefact.map((a: any) => ({
id: a.id, id: a.id,
name: a.name, name: a.name,
description: a.description, description: a.description,
location: a.warehouseArea, // your database location: a.warehouseArea, // your database
earthquakeID: a.earthquakeId?.toString() ?? "", earthquakeID: a.earthquakeId?.toString() ?? "",
observatory: a.type ?? "", // if you want to display type observatory: a.type ?? "", // if you want to display type
dateReleased: a.createdAt ? new Date(a.createdAt).toLocaleDateString() : "", dateReleased: a.createdAt ? new Date(a.createdAt).toLocaleDateString() : "",
image: "/artefactImages/" + (a.imageName || "NoImageFound.PNG"), image: "/artefactImages/" + (a.imageName || "NoImageFound.PNG"),
price: a.shopPrice ?? 100, // fallback price if not in DB price: a.shopPrice ?? 100, // fallback price if not in DB
})); }));
setArtefacts(transformed); setArtefacts(transformed);
} catch (e) { } catch (e) {
// Optionally handle error // Optionally handle error
console.error("Failed to fetch artefacts", e); console.error("Failed to fetch artefacts", e);
} finally { } finally {
setLoading(false); setLoading(false);
} }
} }
fetchArtefacts(); fetchArtefacts();
}, []); }, []);
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [selectedArtefact, setSelectedArtefact] = useState<Artefact | null>(null); const [selectedArtefact, setSelectedArtefact] = useState<Artefact | null>(null);
@ -163,10 +165,15 @@ export default function Shop() {
function handlePay() { function handlePay() {
setError(""); setError("");
if (!validateEmail(email)) { if (email || user?.email) {
setError("Please enter a valid email ending"); if (!validateEmail(email)) {
setError("Please enter a valid email ending");
return;
}
} else {
return; return;
} }
if (!validateCardNumber(cardNumber)) { if (!validateCardNumber(cardNumber)) {
setError("Card number must be 12-19 digits."); setError("Card number must be 12-19 digits.");
return; return;
@ -179,10 +186,13 @@ export default function Shop() {
setError("CVC must be 3 or 4 digits."); setError("CVC must be 3 or 4 digits.");
return; return;
} }
setHiddenArtefactIds((ids) => [...ids, artefact.id]);
// todo create receiving api route // todo create receiving api route
// todo handle sending to api route // todo handle sending to api route
// todo only ask for email if the user is not signed in // todo only ask for email if the user is not signed in
// todo (optional) add create account button to auto-fill email in sign-up modal // todo (optional) add create account button to auto-fill email in sign-up modal
const genOrder = () => "#" + Math.random().toString(36).substring(2, 10).toUpperCase(); const genOrder = () => "#" + Math.random().toString(36).substring(2, 10).toUpperCase();
setOrderNumber(genOrder()); setOrderNumber(genOrder());
onClose(); onClose();
@ -205,15 +215,17 @@ export default function Shop() {
handlePay(); handlePay();
}} }}
> >
<input {!user ? (
className="w-full mb-2 px-3 py-2 border rounded" <input
placeholder="Email Address" className="w-full mb-2 px-3 py-2 border rounded"
value={email} placeholder="Email Address"
onChange={(e) => setEmail(e.target.value)} value={email}
type="email" onChange={(e) => setEmail(e.target.value)}
required type="email"
autoFocus required
/> autoFocus
/>
) : null}
<input <input
className="w-full mb-2 px-3 py-2 border rounded" className="w-full mb-2 px-3 py-2 border rounded"
placeholder="Cardholder Name" placeholder="Cardholder Name"
@ -305,13 +317,15 @@ export default function Shop() {
Artefact Shop Artefact Shop
</h1> </h1>
<p className="text-lg md:text-xl text-center text-white mb-10 drop-shadow-md max-w-2xl"> <p className="text-lg md:text-xl text-center text-white mb-10 drop-shadow-md max-w-2xl">
Discover extraordinary artefacts and collectibles from major seismic events from around the world - Previously studied by our scientists, now Discover extraordinary artefacts and collectibles from major seismic events from around the world - Previously studied
available for purchase. by our scientists, now available for purchase.
</p> </p>
<div className="w-full max-w-7xl grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-10 p-2"> <div className="w-full max-w-7xl grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-10 p-2">
{currentArtefacts.map((artefact) => ( {currentArtefacts
<ArtefactCard key={artefact.id} artefact={artefact} /> .filter((x) => !hiddenArtefactIds.includes(x.id))
))} .map((artefact) => (
<ArtefactCard key={artefact.id} artefact={artefact} />
))}
</div> </div>
<footer className="mt-10 bg-white bg-opacity-90 border-neutral-300 py-3 text-center flex justify-center items-center w-100 max-w-7xl rounded-lg"> <footer className="mt-10 bg-white bg-opacity-90 border-neutral-300 py-3 text-center flex justify-center items-center w-100 max-w-7xl rounded-lg">
<button <button
@ -348,10 +362,11 @@ export default function Shop() {
{showThankYouModal && orderNumber && ( {showThankYouModal && orderNumber && (
<ThankYouModal orderNumber={orderNumber} onClose={() => setShowThankYouModal(false)} /> <ThankYouModal orderNumber={orderNumber} onClose={() => setShowThankYouModal(false)} />
)} )}
{!selectedArtefact && !showPaymentModal && !showThankYouModal && ( {!selectedArtefact && !showPaymentModal && !showThankYouModal && (
<div className="relative z-50"> <div className="relative z-50">
<BottomFooter /> <BottomFooter />
</div> </div>
)} )}
</div> </div>
); );
}