added the mechanism for sort by, added total results and made it all look nice in one row
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user