--- import ebay from "/vendors/ebay.svg?raw"; import SetIcon from '../../components/SetIcon.astro'; import EnergyIcon from '../../components/EnergyIcon.astro'; import RarityIcon from '../../components/RarityIcon.astro'; import { db } from '../../db/index'; import { privateDecrypt } from "node:crypto"; import FirstEditionIcon from "../../components/FirstEditionIcon.astro"; export const partial = true; export const prerender = false; const searchParams = Astro.url.searchParams; const cardId = Number(searchParams.get('cardId')) || 0; // query the database for the card with the given productId and return the card data as json const card = await db.query.cards.findFirst({ where: { cardId: Number(cardId) }, with: { prices: true, set: true, } }); // Get the current card's position in the grid and find previous/next cards // This assumes cards are displayed in a specific order in the DOM const cardElements = typeof document !== 'undefined' ? document.querySelectorAll('[data-card-id]') : []; let prevCardId = null; let nextCardId = null; // Since this is server-side, we can't access the DOM directly // Instead, we'll pass the current cardId and let JavaScript handle navigation // The JS will look for the next/prev cards in the grid based on the visible cards function timeAgo(date: Date | null) { if (!date) return "Not applicable"; const seconds = Math.floor((Date.now() - date.getTime()) / 1000); const intervals: Record = { year: 31536000, month: 2592000, day: 86400, hour: 3600, minute: 60 }; for (const [unit, value] of Object.entries(intervals)) { const count = Math.floor(seconds / value); if (count >= 1) return `${count} ${unit}${count > 1 ? "s" : ""} ago`; } return "just now"; } // Get the most recent calculatedAt across all prices const calculatedAt = (() => { if (!card?.prices?.length) return null; // Extract all valid calculatedAt timestamps const dates = card.prices .map(p => p.calculatedAt) .filter(d => d) // remove null/undefined .map(d => new Date(d)); if (!dates.length) return null; // Return the most recent one return new Date(Math.max(...dates.map(d => d.getTime()))); })(); const conditionOrder = ["Near Mint", "Lightly Played", "Moderately Played", "Heavily Played", "Damaged"]; const conditionAttributes = (price: any) => { const volatility = (() => { const current = price?.marketPrice; const low = price?.lowestPrice; const high = price?.highestPrice; const median = price?.medianPrice; if (current === null || low === null || high === null) return "Indeterminate"; const range = Number(high) - Number(low); if (range <= 0) return "Low"; const position = (Number(current) - Number(low)) / range; if (position > 0.76) return "High"; if (position > 0.49) return "Medium"; return "Low"; })(); // Updated logic: // ❗ If High / Medium / Low → never "alert-secondary" // ❗ If Indeterminate → "alert-secondary" const volatilityClass = (() => { switch (volatility) { case "High": return "alert-danger"; case "Medium": return "alert-warning"; case "Low": return "alert-success"; default: return "alert-secondary"; // Only for Indeterminate } })(); const condition: string = price?.condition || "Near Mint"; return { "Near Mint": { label: "nav-nm", volatility, volatilityClass, class: "show active" }, "Lightly Played": { label: "nav-lp", volatility, volatilityClass }, "Moderately Played": { label: "nav-mp", volatility, volatilityClass }, "Heavily Played": { label: "nav-hp", volatility, volatilityClass }, "Damaged": { label: "nav-dmg", volatility, volatilityClass } }[condition]; }; const ebaySearchUrl = (card: any) => { return `https://www.ebay.com/sch/i.html?_nkw=${encodeURIComponent(card?.productUrlName)}+${encodeURIComponent(card?.set?.setUrlName)}+${encodeURIComponent(card?.number)}&LH_Sold=1&Graded=No&_dcat=183454`; }; ---