added the mechanism for sort by, added total results and made it all look nice in one row

This commit is contained in:
zach
2026-03-16 14:39:55 -04:00
parent 2f17912949
commit ee9f7a2561
4 changed files with 116 additions and 46 deletions

View File

@@ -17,13 +17,31 @@ const facetFields:any = {
"energyType": "Energy Type"
}
// ── Allowed sort values ───────────────────────────────────────────────────
// Maps the client-supplied key to the actual Typesense sort_by string.
// Never pass raw user input directly to sort_by.
// Note: price sorting uses nmMarketPrice — a field you need to denormalize
// onto your card document in your Typesense indexing step (NM market price
// as an integer in cents, e.g. nmMarketPrice: 499 = $4.99).
const sortMap: Record<string, string> = {
'releaseDate:desc,number:asc': '_text_match:asc,releaseDate:desc,number:asc',
'releaseDate:asc,number:asc': '_text_match:asc,releaseDate:asc,number:asc',
'marketPrice:desc': 'marketPrice:desc,releaseDate:desc,number:asc',
'marketPrice:asc': 'marketPrice:asc,releaseDate:desc,number:asc',
'number:asc': '_text_match:asc,number:asc',
'number:desc': '_text_match:asc,number:desc',
};
const DEFAULT_SORT = '_text_match:asc,releaseDate:desc,number:asc';
// get the query from post request using form data
const formData = await Astro.request.formData();
const query = formData.get('q')?.toString() || '';
const start = Number(formData.get('start')?.toString() || '0');
const sortKey = formData.get('sort')?.toString() || '';
const resolvedSort = sortMap[sortKey] ?? DEFAULT_SORT;
const filters = Array.from(formData.entries())
.filter(([key, value]) => key !== 'q' && key !== 'start')
.filter(([key, value]) => key !== 'q' && key !== 'start' && key !== 'sort')
.reduce((acc, [key, value]) => {
if (!acc[key]) {
acc[key] = [];
@@ -57,7 +75,7 @@ let searchArray = [{
facet_by: '',
max_facet_values: 0,
page: Math.floor(start / 20) + 1,
sort_by: '_text_match:asc, releaseDate:desc, number:asc',
sort_by: resolvedSort,
include_fields: '$skus(*)',
}];
@@ -80,7 +98,6 @@ if (start === 0) {
const searchRequests = { searches: searchArray };
const commonSearchParams = {
q: query,
// query_by: 'productLineName,productName,setName,number,rarityName,Artist',
query_by: 'content'
};
@@ -88,10 +105,6 @@ const commonSearchParams = {
const searchResults = await client.multiSearch.perform(searchRequests, commonSearchParams);
const cardResults = searchResults.results[0] as any;
//console.log(util.inspect(cardResults.hits.map((c:any) => { return { productLineName:c.document.productLineName, productName:c.document.productName, setName:c.document.setName, number:c.document.number, rarityName:c.document.rarityName, Artist:c.document.Artist, text_match:c.text_match, text_match_info:c.text_match_info }; }), { showHidden: true, depth: null }));
//console.log(cardResults);
const pokemon = cardResults.hits?.map((hit: any) => hit.document) ?? [];
const totalHits = cardResults?.found;
@@ -165,16 +178,30 @@ const facets = searchResults.results.slice(1).map((result: any) => {
</div>
))}
</div>
<div id="totalResults d-none" class="ms-5 text-secondary" hx-swap-oob="true">
<div id="sortBy" class="mb-2 d-flex align-items-center justify-content-start small" hx-swap-oob="true">
<div class="dropdown">
<button class="btn btn-sm btn-dark dropdown-toggle small" data-bs-toggle="dropdown" aria-expanded="false">Sort by</button>
<ul class="dropdown-menu dropdown-menu-dark">
<li><a class="dropdown-item sort-option small" href="#" data-sort="releaseDate:desc,number:asc" data-label="Set: Newest to Oldest">Set: Newest to Oldest</a></li>
<li><a class="dropdown-item sort-option small" href="#" data-sort="releaseDate:asc,number:asc" data-label="Set: Oldest to Newest">Set: Oldest to Newest</a></li>
<li><a class="dropdown-item sort-option small" href="#" data-sort="marketPrice:desc" data-label="Price: High to Low">Price: High to Low</a></li>
<li><a class="dropdown-item sort-option small" href="#" data-sort="marketPrice:asc" data-label="Price: Low to High">Price: Low to High</a></li>
<li><a class="dropdown-item sort-option small" href="#" data-sort="number:asc" data-label="Card Number: Ascending">Card Number: Ascending</a></li>
<li><a class="dropdown-item sort-option small" href="#" data-sort="number:desc" data-label="Card Number: Descending">Card Number: Descending</a></li>
</ul>
</div>
<span id="sortLabel" class="ms-2 text-secondary">{sortKey ? ({"releaseDate:desc,number:asc":"Set: Newest to Oldest","releaseDate:asc,number:asc":"Set: Oldest to Newest","marketPrice:desc":"Price: High to Low","marketPrice:asc":"Price: Low to High","number:asc":"Card Number: Ascending","number:desc":"Card Number: Descending"}[sortKey] ?? '') : ''}</span>
</div>
<div id="totalResults" class="mb-2 ms-5 text-secondary small" hx-swap-oob="true">
{totalHits} {totalHits === 1 ? ' result' : ' results'}
</div>
<div id="activeFilters" class="d-flex align-items-center small ms-auto" hx-swap-oob="true">
<div id="activeFilters" class="mb-2 d-flex align-items-center small ms-auto" hx-swap-oob="true">
{(Object.entries(filters).length > 0) &&
<span class="me-1">Filtered by:</span>
<span class="me-1 small">Filtered by:</span>
<ul class="list-group list-group-horizontal">
{Object.entries(filters).map(([filter, values]) => (
values.map((value) => (
<li data-facet={filter} data-value={value} class="list-group-item remove-filter">{value}</li>
<li data-facet={filter} data-value={value} class="list-group-item small remove-filter">{value}</li>
))
))}
</ul>