88 lines
2.8 KiB
TypeScript
88 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import DesktopHeader from "../../components/DesktopHeader";
|
|
import MobileHeader from "../../components/MobileHeader";
|
|
import Footer from "../../components/Footer";
|
|
import FilterCard from "../../components/FilterCard";
|
|
|
|
type MerchProduct = {
|
|
id: string;
|
|
name: string;
|
|
unitAmount: number | null;
|
|
currency: string | null;
|
|
thumbnailUrl: string | null;
|
|
variantId: string | null;
|
|
};
|
|
|
|
export default function MerchPage() {
|
|
const [products, setProducts] = useState<MerchProduct[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [message, setMessage] = useState("");
|
|
|
|
useEffect(() => {
|
|
async function load() {
|
|
setLoading(true);
|
|
setMessage("");
|
|
try {
|
|
const res = await fetch("/api/printful/products");
|
|
const data = await res.json();
|
|
if (!res.ok) throw new Error(data.error || "Failed to load merch.");
|
|
setProducts(data.products || []);
|
|
} catch (err: any) {
|
|
setMessage(err.message || "Failed to load merch.");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
load();
|
|
}, []);
|
|
|
|
return (
|
|
<main>
|
|
<DesktopHeader />
|
|
<MobileHeader />
|
|
<section className="section">
|
|
<div className="container layout-2col">
|
|
<aside>
|
|
<FilterCard title="Filter Merch" />
|
|
</aside>
|
|
<div>
|
|
<h1 className="page-title">Merch</h1>
|
|
{message ? <div className="connect-message">{message}</div> : null}
|
|
<div className="products">
|
|
{products.map((product) => (
|
|
<div key={product.id} className="prod">
|
|
<div className="prod__link">
|
|
{product.thumbnailUrl ? (
|
|
<img
|
|
src={product.thumbnailUrl}
|
|
alt={product.name}
|
|
className="prod__img"
|
|
/>
|
|
) : (
|
|
<div className="prod__img prod__img--empty" />
|
|
)}
|
|
<div className="prod__body">
|
|
<div className="prod__title">{product.name}</div>
|
|
<div className="prod__price">
|
|
{product.unitAmount && product.currency
|
|
? `${(product.unitAmount / 100).toFixed(2)} ${product.currency.toUpperCase()}`
|
|
: "Price unavailable"}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
{!products.length && !loading ? (
|
|
<div className="storefront-muted">No merch yet.</div>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<Footer />
|
|
</main>
|
|
);
|
|
}
|