"use client"; import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { Suspense, useCallback, useEffect, useMemo, useState } from "react"; import { useSearchParams } from "next/navigation"; import { ProductSocialBlock } from "@/components/shop/ProductSocialBlock"; import { useCart } from "@/contexts/CartContext"; import { SHOP_PRODUCT_COUNT, SHOP_PRODUCTS, resolveProductImage, shopCategoryCounts, type ShopCurrency, type ShopProduct, } from "@/lib/shopCatalog"; import { estimateUsdForCryptoAmount } from "@/lib/shopFx"; import { getProductSocialMetrics } from "@/lib/shopProductSocial"; import { SHOP_SELLER_COUNT, getSellerById } from "@/lib/shopSellers"; function formatPrice(price: number, currency: ShopCurrency): string { if (currency === "BTC") return price.toFixed(6); if (currency === "ETH") return price.toFixed(4); if (currency === "XMR") return price.toFixed(3); return price.toFixed(2); } const SYM: Record = { BTC: "₿", ETH: "Ξ", USD: "$", XMR: "⏣", }; type SortKey = "relevance" | "price-asc" | "price-desc" | "name"; function MarketContent() { const sp = useSearchParams(); const router = useRouter(); const initialCat = sp.get("category") ?? ""; const [q, setQ] = useState(""); const [category, setCategory] = useState(initialCat); const [sort, setSort] = useState("relevance"); const [currencyFilter, setCurrencyFilter] = useState(""); const [btcUsd, setBtcUsd] = useState(null); const facet = useMemo(() => shopCategoryCounts(), []); useEffect(() => { let cancelled = false; void (async () => { try { const res = await fetch( "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd", { cache: "no-store" }, ); const j = (await res.json()) as { bitcoin?: { usd?: number } }; if (!cancelled && j.bitcoin?.usd && Number.isFinite(j.bitcoin.usd)) setBtcUsd(j.bitcoin.usd); } catch { if (!cancelled) setBtcUsd(96000); } })(); return () => { cancelled = true; }; }, []); const spotBtc = btcUsd ?? 96000; const filtered = useMemo(() => { const ql = q.trim().toLowerCase(); const tokens = ql.split(/\s+/).filter(Boolean); return SHOP_PRODUCTS.filter((p) => { if (category && p.category !== category) return false; if (currencyFilter && p.currency !== currencyFilter) return false; if (tokens.length === 0) return true; const seller = getSellerById(p.sellerId); const sellerHay = seller ? `${seller.handle} ${seller.bio} ${seller.specialty}` : ""; const hay = `${p.name} ${p.description} ${p.category} ${p.id} ${sellerHay}`.toLowerCase(); return tokens.every((t) => hay.includes(t)); }); }, [q, category, currencyFilter]); const sorted = useMemo(() => { const list = [...filtered]; const unitUsd = (p: ShopProduct) => estimateUsdForCryptoAmount(p.price, p.currency, spotBtc); switch (sort) { case "price-asc": return list.sort((a, b) => unitUsd(a) - unitUsd(b)); case "price-desc": return list.sort((a, b) => unitUsd(b) - unitUsd(a)); case "name": return list.sort((a, b) => a.name.localeCompare(b.name)); default: return list; } }, [filtered, sort, spotBtc]); return (

Layer 1 · live floor

{SHOP_PRODUCT_COUNT} SKUs ·{" "} {SHOP_SELLER_COUNT} vendor stalls . Every SKU has a detail page with qty, cart, checkout, or instant USD balance payment. Spot:{" "} ${spotBtc.toLocaleString(undefined, { maximumFractionDigits: 0 })}/BTC.

setQ(e.target.value)} placeholder="title, description, vendor…" className="mt-1 w-full max-w-xl border-2 border-[#00ff41]/30 bg-black/80 px-4 py-2.5 text-sm text-[#c8ffd8] placeholder:text-[#00ff41]/25 focus:border-[#00ff41] focus:outline-none" />
Showing {sorted.length} / {SHOP_PRODUCT_COUNT}
{facet.map((c) => ( ))}
{sorted.map((p) => ( router.push("/checkout")} /> ))}
{sorted.length === 0 ? (

No SKUs match — widen search or pick another category.

) : null}
); } export default function MarketPage() { return ( Loading market…}> ); } function MarketProductCard({ product: p, spotBtc, onBuyNow, }: { product: ShopProduct; spotBtc: number; onBuyNow: () => void; }) { const src = resolveProductImage(p); const local = src.startsWith("/"); const v = getSellerById(p.sellerId); const metrics = getProductSocialMetrics(p.id); const { addToCart, hydrated } = useCart(); const [flash, setFlash] = useState(false); const unitUsd = estimateUsdForCryptoAmount(p.price, p.currency, spotBtc); const add = () => { addToCart(p, 1); setFlash(true); window.setTimeout(() => setFlash(false), 1400); }; const buyNow = () => { addToCart(p, 1); onBuyNow(); }; return (
{p.limited ? ( Limited ) : null}

{p.category}

{p.name}

{v ? (

Seller{" "} {v.handle} · stall ★{v.rating.toFixed(2)}

) : null}

{p.description}

{SYM[p.currency]} {formatPrice(p.price, p.currency)} {p.currency}

≈ ${unitUsd.toFixed(2)} USD

Details
); }