2025-04-13 22:38:33 +01:00
|
|
|
"use client";
|
2025-05-04 16:04:44 +01:00
|
|
|
import Image from "next/image";
|
|
|
|
|
import { Dispatch, SetStateAction, useCallback, useState } from "react";
|
2025-04-28 19:03:29 +01:00
|
|
|
|
2025-05-09 10:30:12 +01:00
|
|
|
import Artefact from "@appTypes/Artefact";
|
2025-05-04 16:04:44 +01:00
|
|
|
import { Currency } from "@appTypes/StoreModel";
|
|
|
|
|
import Sidebar from "@components/Sidebar";
|
|
|
|
|
import { useStoreState } from "@hooks/store";
|
2025-04-13 22:38:33 +01:00
|
|
|
|
2025-05-09 10:30:12 +01:00
|
|
|
// Artefacts Data
|
|
|
|
|
const artefacts: Artefact[] = [
|
2025-04-28 19:03:29 +01:00
|
|
|
{
|
|
|
|
|
id: 1,
|
|
|
|
|
name: "Golden Scarab",
|
2025-05-09 10:30:12 +01:00
|
|
|
description: "An ancient Egyptian artefact symbolizing rebirth.",
|
2025-04-28 19:03:29 +01:00
|
|
|
location: "Cairo, Egypt",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact1.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 150,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 2,
|
|
|
|
|
name: "Aztec Sunstone",
|
|
|
|
|
description: "A replica of the Aztec calendar (inscriptions intact).",
|
|
|
|
|
location: "Peru",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact2.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 200,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 3,
|
|
|
|
|
name: "Medieval Chalice",
|
|
|
|
|
description: "Used by royalty in medieval ceremonies.",
|
|
|
|
|
location: "Cambridge, England",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact3.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 120,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 4,
|
|
|
|
|
name: "Roman Coin",
|
|
|
|
|
description: "An authentic Roman coin from the 2nd century CE.",
|
|
|
|
|
location: "Rome, Italy",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact4.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 80,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 5,
|
|
|
|
|
name: "Samurai Mask",
|
|
|
|
|
description: "Replica of Japanese Samurai battle masks.",
|
|
|
|
|
location: "Tokyo, Japan",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact5.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 300,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 6,
|
|
|
|
|
name: "Ancient Greek Vase",
|
|
|
|
|
description: "Depicts Greek mythology, found in the Acropolis.",
|
|
|
|
|
location: "Athens, Greece",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact6.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 250,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 7,
|
|
|
|
|
name: "Incan Pendant",
|
|
|
|
|
description: "Represents the Sun God Inti.",
|
|
|
|
|
location: "India",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact7.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 175,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 8,
|
|
|
|
|
name: "Persian Carpet Fragment",
|
|
|
|
|
description: "Ancient Persian artistry.",
|
|
|
|
|
location: "Petra, Jordan",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact8.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 400,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 9,
|
|
|
|
|
name: "Stone Buddha",
|
|
|
|
|
description: "Authentic stone Buddha carving.",
|
|
|
|
|
location: "India",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact9.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 220,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 10,
|
|
|
|
|
name: "Victorian Brooch",
|
|
|
|
|
description: "A beautiful Victorian-era brooch with a ruby centre.",
|
|
|
|
|
location: "Oxford, England",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact10.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 150,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 11,
|
|
|
|
|
name: "Ancient Scroll",
|
|
|
|
|
description: "A mysterious scroll from ancient times.",
|
|
|
|
|
location: "Madrid, Spain",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact11.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 500,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 12,
|
|
|
|
|
name: "Ming Dynasty Porcelain",
|
|
|
|
|
description: "Porcelain from China's Ming Dynasty.",
|
|
|
|
|
location: "Beijing, China",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact12.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 300,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 13,
|
|
|
|
|
name: "African Tribal Mask",
|
|
|
|
|
description: "A unique tribal mask from Africa.",
|
|
|
|
|
location: "Nigeria",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact13.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 250,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 14,
|
|
|
|
|
name: "Crystal Skull",
|
2025-05-09 10:30:12 +01:00
|
|
|
description: "A mystical pre-Columbian artefact.",
|
2025-04-28 19:03:29 +01:00
|
|
|
location: "Colombia",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact14.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 1000,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 15,
|
|
|
|
|
name: "Medieval Armor Fragment",
|
|
|
|
|
description: "A fragment of medieval armor.",
|
|
|
|
|
location: "Normandy, France",
|
2025-05-09 10:30:12 +01:00
|
|
|
image: "/artefact15.jpg",
|
2025-04-28 19:03:29 +01:00
|
|
|
price: 400,
|
|
|
|
|
},
|
2025-04-13 22:38:33 +01:00
|
|
|
];
|
|
|
|
|
|
2025-04-14 13:50:13 +01:00
|
|
|
// Modal Component
|
2025-04-13 22:38:33 +01:00
|
|
|
// Shop Component
|
2025-03-17 13:21:02 +00:00
|
|
|
export default function Shop() {
|
2025-04-28 19:03:29 +01:00
|
|
|
const [currentPage, setCurrentPage] = useState(1);
|
2025-05-09 10:30:12 +01:00
|
|
|
const [selectedArtefact, setSelectedArtefact] = useState<Artefact | null>(null); // Track selected artefact for modal
|
|
|
|
|
const artefactsPerPage = 9; // Number of artefacts per page
|
|
|
|
|
const indexOfLastArtefact = currentPage * artefactsPerPage;
|
|
|
|
|
const indexOfFirstArtefact = indexOfLastArtefact - artefactsPerPage;
|
|
|
|
|
const currentArtefacts = artefacts.slice(indexOfFirstArtefact, indexOfLastArtefact);
|
2025-04-28 19:03:29 +01:00
|
|
|
|
|
|
|
|
const selectedCurrency = useStoreState((state) => state.currency.selectedCurrency);
|
|
|
|
|
const conversionRates = useStoreState((state) => state.currency.conversionRates);
|
|
|
|
|
const currencyTickers = useStoreState((state) => state.currency.tickers);
|
|
|
|
|
const convertPrice = useCallback((price: number, currency: Currency) => (price * conversionRates[currency]).toFixed(2), []);
|
2025-04-13 22:38:33 +01:00
|
|
|
|
2025-04-28 19:03:29 +01:00
|
|
|
const handleNextPage = () => {
|
2025-05-09 10:30:12 +01:00
|
|
|
if (indexOfLastArtefact < artefacts.length) {
|
2025-04-28 19:03:29 +01:00
|
|
|
setCurrentPage((prev) => prev + 1);
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-04-13 22:38:33 +01:00
|
|
|
|
2025-04-28 19:03:29 +01:00
|
|
|
const handlePreviousPage = () => {
|
|
|
|
|
if (currentPage > 1) {
|
|
|
|
|
setCurrentPage((prev) => prev - 1);
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-04-14 13:50:13 +01:00
|
|
|
|
2025-05-09 10:30:12 +01:00
|
|
|
function Modal({ artefact }: { artefact: Artefact }) {
|
|
|
|
|
if (!artefact) return null;
|
2025-04-14 13:50:13 +01:00
|
|
|
|
2025-04-28 19:03:29 +01:00
|
|
|
const handleOverlayClick = (e: { target: any; currentTarget: any }) => {
|
|
|
|
|
if (e.target === e.currentTarget) {
|
2025-05-09 10:30:12 +01:00
|
|
|
setSelectedArtefact(null);
|
2025-04-28 19:03:29 +01:00
|
|
|
}
|
|
|
|
|
};
|
2025-04-13 22:38:33 +01:00
|
|
|
|
2025-04-28 19:03:29 +01:00
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className="fixed inset-0 bg-neutral-900 bg-opacity-50 flex justify-center items-center z-50"
|
|
|
|
|
onClick={handleOverlayClick}
|
|
|
|
|
>
|
2025-04-29 16:52:03 +01:00
|
|
|
<div className="bg-white rounded-xl shadow-2xl max-w-lg w-full p-6">
|
2025-05-09 10:30:12 +01:00
|
|
|
<h3 className="text-2xl font-bold mb-4">{artefact.name}</h3>
|
2025-04-29 16:52:03 +01:00
|
|
|
<Image
|
|
|
|
|
height={5000}
|
|
|
|
|
width={5000}
|
2025-05-09 10:30:12 +01:00
|
|
|
src={artefact.image}
|
|
|
|
|
alt={artefact.name}
|
2025-04-29 16:52:03 +01:00
|
|
|
className="w-full h-64 object-cover rounded-md"
|
|
|
|
|
></Image>
|
|
|
|
|
<p className="text-xl font-bold">
|
|
|
|
|
{currencyTickers[selectedCurrency]}
|
2025-05-09 10:30:12 +01:00
|
|
|
{convertPrice(artefact.price, selectedCurrency)}
|
2025-04-29 16:52:03 +01:00
|
|
|
</p>
|
2025-05-09 10:30:12 +01:00
|
|
|
<p className="text-neutral-600 mt-2">{artefact.description}</p>
|
|
|
|
|
<p className="text-neutral-500 font-bold mt-1">Location: {artefact.location}</p>
|
2025-04-29 16:52:03 +01:00
|
|
|
|
|
|
|
|
<div className="flex justify-end gap-4 mt-4 mr-2">
|
2025-04-28 19:03:29 +01:00
|
|
|
<button
|
|
|
|
|
onClick={() => alert("Purchased Successfully!")}
|
2025-04-29 16:52:03 +01:00
|
|
|
className="px-10 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
|
2025-04-28 19:03:29 +01:00
|
|
|
>
|
|
|
|
|
Buy
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-04-14 13:50:13 +01:00
|
|
|
|
2025-05-09 10:30:12 +01:00
|
|
|
// ArtefactCard Component
|
|
|
|
|
function ArtefactCard({ artefact }: { artefact: Artefact }) {
|
2025-04-28 19:03:29 +01:00
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className="flex flex-col bg-white shadow-md rounded-md overflow-hidden cursor-pointer hover:scale-105 transition-transform"
|
2025-05-09 10:30:12 +01:00
|
|
|
onClick={() => setSelectedArtefact(artefact)} // Opens modal
|
2025-04-28 19:03:29 +01:00
|
|
|
>
|
2025-05-09 10:30:12 +01:00
|
|
|
<img src={artefact.image} alt={artefact.name} className="w-full h-56 object-cover" />
|
2025-04-28 19:03:29 +01:00
|
|
|
<div className="p-4">
|
2025-05-09 10:30:12 +01:00
|
|
|
<h3 className="text-lg font-semibold">{artefact.name}</h3>
|
|
|
|
|
<p className="text-neutral-500 mb-2">{artefact.location}</p>
|
2025-04-29 16:52:03 +01:00
|
|
|
<p className="text-black font-bold text-md mt-2">
|
2025-04-28 19:03:29 +01:00
|
|
|
{currencyTickers[selectedCurrency]}
|
2025-05-09 10:30:12 +01:00
|
|
|
{convertPrice(artefact.price, selectedCurrency)}
|
2025-04-28 19:03:29 +01:00
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-04-13 22:38:33 +01:00
|
|
|
|
2025-04-28 19:03:29 +01:00
|
|
|
return (
|
|
|
|
|
<div className="flex flex-col min-h-screen bg-neutral-100">
|
|
|
|
|
{/* Main Content */}
|
2025-05-06 08:34:16 +01:00
|
|
|
<div className="flex flex-1 overflow-y-auto">
|
2025-05-09 10:30:12 +01:00
|
|
|
{/* Artefact Grid */}
|
2025-05-06 08:34:16 +01:00
|
|
|
<div className="flex-grow grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 p-6">
|
2025-05-09 10:30:12 +01:00
|
|
|
{currentArtefacts.map((artefact) => (
|
|
|
|
|
<ArtefactCard key={artefact.id} artefact={artefact} />
|
2025-04-28 19:03:29 +01:00
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-04-29 16:52:03 +01:00
|
|
|
|
2025-04-28 19:03:29 +01:00
|
|
|
{/* Pagination Footer */}
|
2025-05-06 08:34:16 +01:00
|
|
|
<footer className="mt-10 bg-white border-t border-neutral-300 py-3 text-center flex justify-center items-center">
|
2025-04-28 19:03:29 +01:00
|
|
|
<button
|
|
|
|
|
onClick={handlePreviousPage}
|
|
|
|
|
disabled={currentPage === 1}
|
2025-04-29 16:52:03 +01:00
|
|
|
className={`mx-2 px-4 py-1 bg-blue-500 text-white rounded-md font-bold shadow-md ${
|
2025-04-28 19:03:29 +01:00
|
|
|
currentPage === 1 ? "opacity-50 cursor-not-allowed" : "hover:bg-blue-600"
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
← Previous
|
|
|
|
|
</button>
|
2025-04-29 16:52:03 +01:00
|
|
|
<p className="mx-3 text-lg font-bold">{currentPage}</p>
|
2025-04-28 19:03:29 +01:00
|
|
|
<button
|
|
|
|
|
onClick={handleNextPage}
|
2025-05-09 10:30:12 +01:00
|
|
|
disabled={indexOfLastArtefact >= artefacts.length}
|
2025-04-28 19:03:29 +01:00
|
|
|
className={`mx-2 px-4 py-1 bg-blue-500 text-white rounded-md font-bold shadow-md ${
|
2025-05-09 10:30:12 +01:00
|
|
|
indexOfLastArtefact >= artefacts.length ? "opacity-50 cursor-not-allowed" : "hover:bg-blue-600"
|
2025-04-28 19:03:29 +01:00
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
Next →
|
|
|
|
|
</button>
|
|
|
|
|
</footer>
|
|
|
|
|
{/* Modal */}
|
2025-05-09 10:30:12 +01:00
|
|
|
{selectedArtefact && <Modal artefact={selectedArtefact} />}
|
2025-04-28 19:03:29 +01:00
|
|
|
</div>
|
|
|
|
|
);
|
2025-04-14 13:50:13 +01:00
|
|
|
}
|