added a button group for quick filtering by productLine
This commit is contained in:
@@ -18,11 +18,6 @@ const facetFields:any = {
|
||||
}
|
||||
|
||||
// ── 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',
|
||||
@@ -40,8 +35,16 @@ const start = Number(formData.get('start')?.toString() || '0');
|
||||
const sortKey = formData.get('sort')?.toString() || '';
|
||||
const resolvedSort = sortMap[sortKey] ?? DEFAULT_SORT;
|
||||
|
||||
// ── Language filter ───────────────────────────────────────────────────────
|
||||
// Expects a `language` field on your card documents in Typesense.
|
||||
// Valid values: 'en', 'jp' — anything else (or 'all') means no filter.
|
||||
const language = formData.get('language')?.toString() || 'all';
|
||||
const languageFilter = language === 'en' ? " && productLineName:=`Pokemon`"
|
||||
: language === 'jp' ? " && productLineName:=`Pokemon Japan`"
|
||||
: '';
|
||||
|
||||
const filters = Array.from(formData.entries())
|
||||
.filter(([key, value]) => key !== 'q' && key !== 'start' && key !== 'sort')
|
||||
.filter(([key]) => key !== 'q' && key !== 'start' && key !== 'sort' && key !== 'language')
|
||||
.reduce((acc, [key, value]) => {
|
||||
if (!acc[key]) {
|
||||
acc[key] = [];
|
||||
@@ -63,14 +66,15 @@ const facetFilter = (facet:string) => {
|
||||
.filter(([field]) => field !== facet)
|
||||
.map(([field, values]) => `${field}:=[${values.map(v => '`'+v+'`').join(',')}]`)
|
||||
.join(' && ');
|
||||
return `sealed:false${otherFilters ? ` && ${otherFilters}` : ''}`;
|
||||
// Language filter is always included so facet counts stay accurate
|
||||
return `sealed:false${languageFilter}${otherFilters ? ` && ${otherFilters}` : ''}`;
|
||||
};
|
||||
|
||||
|
||||
// primary search values (for cards)
|
||||
let searchArray = [{
|
||||
collection: 'cards',
|
||||
filter_by: `sealed:false${filterBy ? ` && ${filterBy}` : ''}`,
|
||||
filter_by: `sealed:false${languageFilter}${filterBy ? ` && ${filterBy}` : ''}`,
|
||||
per_page: 20,
|
||||
facet_by: '',
|
||||
max_facet_values: 0,
|
||||
@@ -135,8 +139,8 @@ const facetNames = (name:string) => {
|
||||
}
|
||||
|
||||
const facets = searchResults.results.slice(1).map((result: any) => {
|
||||
const facet = result.facet_counts[0];
|
||||
if (!facet) return facet;
|
||||
const facet = result.facet_counts?.[0];
|
||||
if (!facet) return null;
|
||||
|
||||
// Sort: checked items first, then alphabetically
|
||||
facet.counts = facet.counts.sort((a: any, b: any) => {
|
||||
@@ -148,7 +152,7 @@ const facets = searchResults.results.slice(1).map((result: any) => {
|
||||
});
|
||||
|
||||
return facet;
|
||||
});
|
||||
}).filter(Boolean);
|
||||
|
||||
---
|
||||
|
||||
@@ -178,19 +182,24 @@ const facets = searchResults.results.slice(1).map((result: any) => {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div id="sortBy" class="d-flex flex-fill align-items-center me-auto" hx-swap-oob="true">
|
||||
<div id="sortBy" class="d-flex flex-fill align-items-center me-auto gap-2 small" hx-swap-oob="true">
|
||||
<div class="btn-group btn-group-sm ms-2 flex-shrink-0" role="group" aria-label="Language filter">
|
||||
<button type="button" class={`btn btn-outline-secondary language-btn${language === 'all' ? ' active' : ''}`} data-lang="all">All</button>
|
||||
<button type="button" class={`btn btn-outline-secondary language-btn${language === 'en' ? ' active' : ''}`} data-lang="en">EN</button>
|
||||
<button type="button" class={`btn btn-outline-secondary language-btn${language === 'jp' ? ' active' : ''}`} data-lang="jp">JP</button>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-dark dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Sort by</button>
|
||||
<ul class="dropdown-menu dropdown-menu-dark">
|
||||
<li><a class="dropdown-item sort-option" 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" 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" href="#" data-sort="marketPrice:desc" data-label="Price: High to Low">Price: High to Low</a></li>
|
||||
<li><a class="dropdown-item sort-option" href="#" data-sort="marketPrice:asc" data-label="Price: Low to High">Price: Low to High</a></li>
|
||||
<li><a class="dropdown-item sort-option" href="#" data-sort="number:asc" data-label="Card Number: Ascending">Card Number: Ascending</a></li>
|
||||
<li><a class="dropdown-item sort-option" href="#" data-sort="number:desc" data-label="Card Number: Descending">Card Number: Descending</a></li>
|
||||
<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-1 text-secondary small">{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>
|
||||
<span id="sortLabel" class="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="d-flex text-secondary small d-none align-items-center" hx-swap-oob="true">
|
||||
{totalHits} {totalHits === 1 ? ' result' : ' results'}
|
||||
|
||||
Reference in New Issue
Block a user