Files
pokemon/src/pages/partials/cards.astro

96 lines
4.0 KiB
Plaintext
Raw Normal View History

2026-02-17 13:07:29 -05:00
---
2026-02-25 23:20:45 -05:00
import { client } from '../../db/typesense';
2026-02-22 11:00:30 -05:00
import { db } from '../../db';
import RarityIcon from '../../components/RarityIcon.astro';
2026-02-17 13:07:29 -05:00
2026-02-22 11:00:30 -05:00
export const prerender = false;
// get the query from post request using form data
const formData = await Astro.request.formData();
const query = formData.get('q')?.toString() || '';
2026-02-23 08:33:11 -05:00
const start = Number(formData.get('start')?.toString() || '0');
2026-02-22 11:00:30 -05:00
// use typesense to search for cards matching the query and return the productIds of the results
2026-02-17 13:27:48 -05:00
const searchResults = await client.collections('cards').documents().search({
q: query,
2026-02-22 11:00:30 -05:00
filter_by: 'sealed:false',
2026-02-23 09:23:03 -05:00
query_by: 'productLineName,productName,setName,number,rarityName,Artist',
2026-02-23 08:33:11 -05:00
per_page: 20,
page: Math.floor(start / 20) + 1,
2026-02-17 13:27:48 -05:00
});
2026-02-17 13:42:00 -05:00
const productIds = searchResults.hits?.map((hit: any) => hit.document.productId) ?? [];
2026-02-23 08:33:11 -05:00
const totalHits = searchResults.found;
2026-02-17 13:27:48 -05:00
// get pokemon data with prices and set info using searchResults and then query the database for each card to get the prices and set info
2026-02-17 13:07:29 -05:00
const pokemon = await db.query.cards.findMany({
2026-02-17 13:27:48 -05:00
where: { productId: { in: productIds, }, },
2026-02-17 13:07:29 -05:00
with: {
prices: true,
set: true,
}
});
2026-02-22 11:00:30 -05:00
// format price to 2 decimal places (or 0 if price >=100) and adds a $ sign, if the price is null it returns ""
2026-02-17 13:07:29 -05:00
const formatPrice = (price:any) => {
if (price === null) {
return "—";
}
2026-02-17 13:07:29 -05:00
price = Number(price);
2026-02-22 11:00:30 -05:00
if (price > 99.99) return `$${Math.round(price)}`;
return `$${price.toFixed(2)}`;
2026-02-17 13:07:29 -05:00
};
2026-02-22 11:00:30 -05:00
const conditionOrder = ["Near Mint", "Lightly Played", "Moderately Played", "Heavily Played", "Damaged"];
2026-02-25 23:20:45 -05:00
const conditionShort = (condition:string) => {
return {
"Near Mint": "NM",
"Lightly Played": "LP",
"Moderately Played": "MP",
"Heavily Played": "HP",
"Damaged": "DMG"
}[condition] || condition.split(' ').map((w) => w[0]).join('');
}
2026-02-25 14:12:11 -05:00
2026-02-17 13:07:29 -05:00
---
2026-02-23 08:33:11 -05:00
{(start === 0) &&
<script define:vars={{ totalHits }} is:inline>
let hits = totalHits;
</script>
}
2026-02-17 13:07:29 -05:00
{pokemon.map((card) => (
<div class="col">
<div class="inventory-button position-relative float-end shadow-filter text-center d-none">
<div class="inventory-label pt-2">+/-</div>
</div>
2026-02-25 14:12:11 -05:00
<div hx-get={`/partials/card-modal?cardId=${card.cardId}`} hx-target="#cardModal" hx-trigger="click" data-bs-toggle="modal" data-bs-target="#cardModal" onclick="const cardTitle = this.querySelector('#cardImage').getAttribute('alt'); dataLayer.push({'event': 'virtualPageview', 'pageUrl': this.getAttribute('hx-get'), 'pageTitle': cardTitle, 'previousUrl': '/pokemon'});">
<img src={`/cards/${card.productId}.jpg`} alt={card.productName} id="cardImage" loading="lazy" decoding="async" class="img-fluid rounded-3 mb-2 card-image image-grow w-100" onerror="this.onerror=null;this.src='/cards/noImage.webp'"/>
</div>
<div class="row row-cols-5 gx-1 price-row mb-2">
2026-02-17 13:07:29 -05:00
{card.prices
.slice()
2026-02-22 11:00:30 -05:00
.sort((a, b) => conditionOrder.indexOf(a.condition) - conditionOrder.indexOf(b.condition))
2026-02-17 13:07:29 -05:00
.filter((price, index, arr) =>
arr.findIndex(p => p.condition === price.condition) === index
)
.map((price) => (
<div class="col price-label ps-1">
2026-02-25 23:20:45 -05:00
{ conditionShort(price.condition) }
2026-02-22 11:00:30 -05:00
<br />{formatPrice(price.marketPrice)}
2026-02-17 13:07:29 -05:00
</div>
))}
</div>
<div class="h5 my-0">{card.productName}</div>
<div class="d-flex flex-row lh-1 mt-1">
<div class="text-secondary flex-grow-1">{card.set?.setCode}</div>
<div class="text-secondary">{card.number}</div>
<span class="ps-2 small-icon"><RarityIcon rarity={card.rarityName} /></span>
</div>
2026-02-24 12:36:19 -05:00
<div>{card.variant}<span class="d-none">{card.productId}</span></div>
2026-02-17 13:07:29 -05:00
</div>
2026-02-25 14:12:11 -05:00
2026-02-22 11:00:30 -05:00
))}
2026-02-23 08:33:11 -05:00
{start + 20 < totalHits &&
<div hx-post="/partials/cards" hx-trigger="revealed" hx-include="#searchform" hx-target="#cardGrid" hx-swap="beforeend" hx-on--after-request="afterUpdate(event)">
Loading...
</div>
2026-02-25 14:12:11 -05:00
}