[wip] bugs to work out, but backend should support inventory
This commit is contained in:
@@ -88,6 +88,25 @@ export const createSkuCollection = async () => {
|
|||||||
console.log(chalk.green('Collection "skus" created successfully.'));
|
console.log(chalk.green('Collection "skus" created successfully.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete and recreate the 'inventory' index
|
||||||
|
export const createInventoryCollection = async () => {
|
||||||
|
try {
|
||||||
|
await client.collections('inventories').delete();
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore error, just means collection doesn't exist
|
||||||
|
}
|
||||||
|
await client.collections().create({
|
||||||
|
name: 'inventories',
|
||||||
|
fields: [
|
||||||
|
{ name: 'id', type: 'string' },
|
||||||
|
{ name: 'userId', type: 'string' },
|
||||||
|
{ name: 'catalogName', type: 'string' },
|
||||||
|
{ name: 'card_id', type: 'string', reference: 'cards.id' },
|
||||||
|
]
|
||||||
|
});
|
||||||
|
console.log(chalk.green('Collection "inventories" created successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const upsertCardCollection = async (db:DBInstance) => {
|
export const upsertCardCollection = async (db:DBInstance) => {
|
||||||
const pokemon = await db.query.cards.findMany({
|
const pokemon = await db.query.cards.findMany({
|
||||||
@@ -131,6 +150,17 @@ export const upsertSkuCollection = async (db:DBInstance) => {
|
|||||||
console.log(chalk.green('Collection "skus" indexed successfully.'));
|
console.log(chalk.green('Collection "skus" indexed successfully.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const upsertInventoryCollection = async (db:DBInstance) => {
|
||||||
|
const inv = await db.query.inventory.findMany();
|
||||||
|
await client.collections('inventories').documents().import(inv.map(i => ({
|
||||||
|
id: i.inventoryId,
|
||||||
|
userId: i.userId,
|
||||||
|
catalogName: i.catalogName,
|
||||||
|
card_id: i.cardId.toString(),
|
||||||
|
})), { action: 'upsert' });
|
||||||
|
console.log(chalk.green('Collection "inventories" indexed successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,10 @@ import * as Indexing from './pokemon-helper.ts';
|
|||||||
|
|
||||||
//await Indexing.createCardCollection();
|
//await Indexing.createCardCollection();
|
||||||
//await Indexing.createSkuCollection();
|
//await Indexing.createSkuCollection();
|
||||||
await Indexing.upsertCardCollection(db);
|
await Indexing.createInventoryCollection();
|
||||||
await Indexing.upsertSkuCollection(db);
|
|
||||||
|
//await Indexing.upsertCardCollection(db);
|
||||||
|
//await Indexing.upsertSkuCollection(db);
|
||||||
|
await Indexing.upsertInventoryCollection(db);
|
||||||
await ClosePool();
|
await ClosePool();
|
||||||
console.log(chalk.green('Pokémon reindex complete.'));
|
console.log(chalk.green('Pokémon reindex complete.'));
|
||||||
|
|||||||
@@ -21,9 +21,21 @@ export const relations = defineRelations(schema, (r) => ({
|
|||||||
}),
|
}),
|
||||||
history: r.many.priceHistory(),
|
history: r.many.priceHistory(),
|
||||||
latestSales: r.many.salesHistory(),
|
latestSales: r.many.salesHistory(),
|
||||||
|
inventories: r.many.inventory(),
|
||||||
|
},
|
||||||
|
inventory: {
|
||||||
|
card: r.one.cards({
|
||||||
|
from: r.inventory.cardId,
|
||||||
|
to: r.cards.cardId,
|
||||||
|
}),
|
||||||
|
sku: r.one.skus({
|
||||||
|
from: [r.inventory.cardId, r.inventory.condition],
|
||||||
|
to: [r.skus.cardId, r.skus.condition],
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
cards: {
|
cards: {
|
||||||
prices: r.many.skus(),
|
prices: r.many.skus(),
|
||||||
|
inventories: r.many.inventory(),
|
||||||
set: r.one.sets({
|
set: r.one.sets({
|
||||||
from: r.cards.setId,
|
from: r.cards.setId,
|
||||||
to: r.sets.setId,
|
to: r.sets.setId,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//import { mysqlTable, int, varchar, boolean, decimal, datetime, index } from "drizzle-orm/mysql-core"
|
//import { mysqlTable, int, varchar, boolean, decimal, datetime, index } from "drizzle-orm/mysql-core"
|
||||||
import { integer, varchar, boolean, decimal, timestamp, index, pgSchema, uniqueIndex, primaryKey } from "drizzle-orm/pg-core";
|
import { integer, varchar, boolean, decimal, timestamp, index, pgSchema, uuid, primaryKey } from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
export const pokeSchema = pgSchema("pokemon");
|
export const pokeSchema = pgSchema("pokemon");
|
||||||
|
|
||||||
@@ -98,6 +98,7 @@ export const skus = pokeSchema.table('skus', {
|
|||||||
},
|
},
|
||||||
(table) => [
|
(table) => [
|
||||||
index('idx_product_id_condition').on(table.productId, table.variant, table.condition),
|
index('idx_product_id_condition').on(table.productId, table.variant, table.condition),
|
||||||
|
index('idx_card_id_condition').on(table.cardId, table.condition),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const priceHistory = pokeSchema.table('price_history', {
|
export const priceHistory = pokeSchema.table('price_history', {
|
||||||
@@ -124,6 +125,20 @@ export const salesHistory = pokeSchema.table('sales_history',{
|
|||||||
primaryKey({ name: 'pk_sales_history', columns: [table.skuId, table.orderDate] })
|
primaryKey({ name: 'pk_sales_history', columns: [table.skuId, table.orderDate] })
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
export const inventory = pokeSchema.table('inventory',{
|
||||||
|
inventoryId: uuid().primaryKey().notNull().defaultRandom(),
|
||||||
|
userId: varchar({ length: 100 }).notNull(),
|
||||||
|
catalogName: varchar({ length: 100 }),
|
||||||
|
cardId: integer().notNull(),
|
||||||
|
condition: varchar({ length: 255 }).notNull(),
|
||||||
|
quantity: integer(),
|
||||||
|
purchasePrice: integer(),
|
||||||
|
note: varchar({ length:255 })
|
||||||
|
},
|
||||||
|
(table) => [
|
||||||
|
index('idx_userid_cardid').on(table.userId, table.cardId)
|
||||||
|
]);
|
||||||
|
|
||||||
export const processingSkus = pokeSchema.table('processing_skus', {
|
export const processingSkus = pokeSchema.table('processing_skus', {
|
||||||
skuId: integer().primaryKey(),
|
skuId: integer().primaryKey(),
|
||||||
});
|
});
|
||||||
|
|||||||
161
src/pages/api/inventory.ts
Normal file
161
src/pages/api/inventory.ts
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
import type { APIRoute } from 'astro';
|
||||||
|
import { db } from '../../db/index';
|
||||||
|
import { inventory } from '../../db/schema';
|
||||||
|
import { client } from '../../db/typesense';
|
||||||
|
import { eq } from 'drizzle-orm';
|
||||||
|
|
||||||
|
|
||||||
|
const GainLoss = (purchasePrice:any, marketPrice:any) => {
|
||||||
|
if (!purchasePrice || !marketPrice) return '<div class="fs-5 fw-semibold">N/A</div>';
|
||||||
|
const pp = Number(purchasePrice);
|
||||||
|
const mp = Number(marketPrice);
|
||||||
|
if (pp === mp) return '<div class="fs-5 fw-semibold text-warning">-</div>';
|
||||||
|
if (pp > mp) return `<div class="fs-5 fw-semibold text-critical">-$${pp-mp}</div>`;
|
||||||
|
return `<div class="fs-5 fw-semibold text-success">+$${mp-pp}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const getInventory = async (userId:string, cardId:number) => {
|
||||||
|
|
||||||
|
const inventories = await db.query.inventory.findMany({
|
||||||
|
where: { userId:userId, cardId:cardId, },
|
||||||
|
with: { card: true, sku: true, }
|
||||||
|
});
|
||||||
|
|
||||||
|
const invHtml = inventories.map(inv => {
|
||||||
|
return `
|
||||||
|
<article class="border rounded-4 p-2 bg-body-tertiary inventory-entry-card">
|
||||||
|
<div class="d-flex flex-column gap-2">
|
||||||
|
<!-- Top row -->
|
||||||
|
<div class="d-flex justify-content-between align-items-start gap-3">
|
||||||
|
<div class="min-w-0 flex-grow-1">
|
||||||
|
<div class="fw-semibold fs-5 text-body mb-1">${inv.condition}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Middle row -->
|
||||||
|
<div class="row g-2">
|
||||||
|
<div class="col-4">
|
||||||
|
<div class="small text-secondary">Purchase price</div>
|
||||||
|
<div class="fs-5 fw-semibold">$${inv.purchasePrice}</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<div class="small text-secondary">Market price</div>
|
||||||
|
<div class="fs-5 text-success">$${inv.sku?.marketPrice}</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<div class="small text-secondary">Gain / loss</div>
|
||||||
|
${GainLoss(inv.purchasePrice, inv.sku?.marketPrice)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Bottom row -->
|
||||||
|
<div class="d-flex justify-content-between align-items-center gap-3 flex-wrap">
|
||||||
|
<div class="d-flex align-items-center gap-2">
|
||||||
|
<span class="small text-secondary">Qty</span>
|
||||||
|
<div class="btn-group" role="group" aria-label="Quantity controls">
|
||||||
|
<button type="button" class="btn btn-outline-secondary btn-sm">−</button>
|
||||||
|
<button type="button" class="btn btn-outline-secondary btn-sm" tabindex="-1">${inv.quantity}</button>
|
||||||
|
<button type="button" class="btn btn-outline-secondary btn-sm">+</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center gap-2 flex-wrap">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary">Edit</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-danger">Remove</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
invHtml.join(''),
|
||||||
|
{
|
||||||
|
status: 200,
|
||||||
|
headers: { 'Content-Type': 'text/html' },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const addToInventory = async (userId:string, cardId:number, condition:string, purchasePrice:number, quantity:number, note:string, catalogName:string) => {
|
||||||
|
// First add to database
|
||||||
|
const inv = await db.insert(inventory).values({
|
||||||
|
userId: userId,
|
||||||
|
cardId: cardId,
|
||||||
|
catalogName: catalogName,
|
||||||
|
condition: condition,
|
||||||
|
purchasePrice: purchasePrice,
|
||||||
|
quantity: quantity,
|
||||||
|
note: note,
|
||||||
|
}).returning();
|
||||||
|
// And then add to Typesense
|
||||||
|
await client.collections('inventories').documents().import(inv.map(i => ({
|
||||||
|
id: i.inventoryId,
|
||||||
|
userId: i.userId,
|
||||||
|
catalogName: i.catalogName,
|
||||||
|
card_id: i.cardId.toString(),
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeFromInventory = async (inventoryId:string) => {
|
||||||
|
await db.delete(inventory).where(eq( inventory.inventoryId, inventoryId ));
|
||||||
|
await client.collections('inventories').documents(inventoryId).delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateInventory = async (inventoryId:string, quantity:number, purchasePrice:number, note:string) => {
|
||||||
|
// Update in database
|
||||||
|
await db.update(inventory).set({
|
||||||
|
quantity: quantity,
|
||||||
|
purchasePrice: purchasePrice,
|
||||||
|
note: note,
|
||||||
|
}).where(eq( inventory.inventoryId, inventoryId ));
|
||||||
|
// There is no need to update Typesense for these fields as they are not indexed
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST: APIRoute = async ({ request, locals }) => {
|
||||||
|
// Access form data from the request body
|
||||||
|
const formData = await request.formData();
|
||||||
|
const action = formData.get('action');
|
||||||
|
const cardId = Number(formData.get('cardId')) || 0;
|
||||||
|
const { userId } = locals.auth();
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
|
||||||
|
case 'add':
|
||||||
|
const condition = formData.get('condition')?.toString() || 'Unknown';
|
||||||
|
const purchasePrice = Number(formData.get('purchasePrice')) || 0;
|
||||||
|
const quantity = Number(formData.get('quantity')) || 1;
|
||||||
|
const note = formData.get('note')?.toString() || '';
|
||||||
|
const catalogName = formData.get('catalogName')?.toString() || 'Default';
|
||||||
|
await addToInventory(userId!, cardId, condition, purchasePrice, quantity, note, catalogName);
|
||||||
|
//return await getInventory(cardId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'remove':
|
||||||
|
const inventoryId = formData.get('inventoryId')?.toString() || '';
|
||||||
|
await removeFromInventory(inventoryId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'update':
|
||||||
|
const invId = formData.get('inventoryId')?.toString() || '';
|
||||||
|
const qty = Number(formData.get('quantity')) || 1;
|
||||||
|
const price = Number(formData.get('purchasePrice')) || 0;
|
||||||
|
const invNote = formData.get('note')?.toString() || '';
|
||||||
|
await updateInventory(invId, qty, price, invNote);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return new Response(
|
||||||
|
'Invalid action',
|
||||||
|
{
|
||||||
|
status: 400,
|
||||||
|
headers: { 'Content-Type': 'text/html' }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always return current inventory
|
||||||
|
return getInventory(userId!, cardId);
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
@@ -1028,7 +1028,7 @@ const totalGain = inventory.reduce((s, c) => s + gain(c) * c.qty, 0);
|
|||||||
document.getElementById("catalogList")?.appendChild(li);
|
document.getElementById("catalogList")?.appendChild(li);
|
||||||
|
|
||||||
input.value = "";
|
input.value = "";
|
||||||
bootstrap.Modal.getInstance(document.getElementById("newCatalogModal"))?.hide();
|
//bootstrap.Modal.getInstance(document.getElementById("newCatalogModal"))?.hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById("csvFileInput")?.addEventListener("change", (e) => {
|
document.getElementById("csvFileInput")?.addEventListener("change", (e) => {
|
||||||
|
|||||||
@@ -169,7 +169,6 @@ const altSearchUrl = (card: any) => {
|
|||||||
return `https://alt.xyz/browse?query=${encodeURIComponent(card?.productUrlName)}+${encodeURIComponent(card?.set?.setUrlName)}+${encodeURIComponent(card?.number)}&sortBy=newest_first`;
|
return `https://alt.xyz/browse?query=${encodeURIComponent(card?.productUrlName)}+${encodeURIComponent(card?.set?.setUrlName)}+${encodeURIComponent(card?.number)}&sortBy=newest_first`;
|
||||||
};
|
};
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="modal-dialog modal-dialog-centered modal-fullscreen-md-down modal-xl">
|
<div class="modal-dialog modal-dialog-centered modal-fullscreen-md-down modal-xl">
|
||||||
<div class="modal-content" data-card-id={card?.cardId}>
|
<div class="modal-content" data-card-id={card?.cardId}>
|
||||||
<div class="modal-header border-0">
|
<div class="modal-header border-0">
|
||||||
@@ -496,105 +495,22 @@ const altSearchUrl = (card: any) => {
|
|||||||
<div class="alert alert-dark border-0 rounded-4 d-none" id="inventoryEmptyState">
|
<div class="alert alert-dark border-0 rounded-4 d-none" id="inventoryEmptyState">
|
||||||
<div class="fw-medium mb-1">No inventory entries yet</div>
|
<div class="fw-medium mb-1">No inventory entries yet</div>
|
||||||
<div class="text-secondary small">
|
<div class="text-secondary small">
|
||||||
Once you add copies of this card, they’ll show up here.
|
Once you add copies of this card, they'll show up here.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Inventory list -->
|
<!-- Inventory list -->
|
||||||
<div class="d-flex flex-column gap-3" id="inventoryEntryList">
|
<div class="d-flex flex-column gap-3" id="inventoryEntryList" hx-post="/api/inventory" hx-trigger="intersect once" hx-target="this" hx-vals=`{"cardId": ${cardId}}`>
|
||||||
|
<span>Loading...</span>
|
||||||
<!-- Inventory card -->
|
|
||||||
<article class="border rounded-4 p-2 bg-body-tertiary inventory-entry-card">
|
|
||||||
<div class="d-flex flex-column gap-2">
|
|
||||||
|
|
||||||
<!-- Top row -->
|
|
||||||
<div class="d-flex justify-content-between align-items-start gap-3">
|
|
||||||
<div class="min-w-0 flex-grow-1">
|
|
||||||
<div class="fw-semibold fs-5 text-body mb-1">Near Mint</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Middle row -->
|
|
||||||
<div class="row g-2">
|
|
||||||
<div class="col-4">
|
|
||||||
<div class="small text-secondary">Purchase price</div>
|
|
||||||
<div class="fs-5 fw-semibold">$8.50</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
<div class="small text-secondary">Market price</div>
|
|
||||||
<div class="fs-5 text-success">$10.25</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
<div class="small text-secondary">Gain / loss</div>
|
|
||||||
<div class="fs-5 fw-semibold text-success">+$1.75</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Bottom row -->
|
|
||||||
<div class="d-flex justify-content-between align-items-center gap-3 flex-wrap">
|
|
||||||
<div class="d-flex align-items-center gap-2">
|
|
||||||
<span class="small text-secondary">Qty</span>
|
|
||||||
|
|
||||||
<div class="btn-group" role="group" aria-label="Quantity controls">
|
|
||||||
<button type="button" class="btn btn-outline-secondary btn-sm">−</button>
|
|
||||||
<button type="button" class="btn btn-outline-secondary btn-sm" tabindex="-1">2</button>
|
|
||||||
<button type="button" class="btn btn-outline-secondary btn-sm">+</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-flex align-items-center gap-2 flex-wrap">
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary">Edit</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-danger">Remove</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<!-- Inventory card -->
|
|
||||||
<article class="border rounded-4 p-2 bg-body-tertiary inventory-entry-card">
|
|
||||||
<div class="d-flex flex-column gap-2">
|
|
||||||
|
|
||||||
<!-- Top row -->
|
|
||||||
<div class="d-flex justify-content-between align-items-start gap-3">
|
|
||||||
<div class="min-w-0 flex-grow-1">
|
|
||||||
<div class="fw-semibold fs-5 text-body mb-1">Lightly Played</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row g-2">
|
|
||||||
<div class="col-4">
|
|
||||||
<div class="small text-secondary">Purchase price</div>
|
|
||||||
<div class="fs-5 fw-semibold">$6.00</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
<div class="small text-secondary">Market price</div>
|
|
||||||
<div class="fs-5 text-success">$8.00</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
<div class="small text-secondary">Gain / loss</div>
|
|
||||||
<div class="fs-5 fw-semibold text-success">+$4.00</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-flex justify-content-between align-items-center gap-3 flex-wrap">
|
|
||||||
<div class="d-flex align-items-center gap-2">
|
|
||||||
<span class="small text-secondary">Qty</span>
|
|
||||||
<div class="btn-group" role="group" aria-label="Quantity controls">
|
|
||||||
<button type="button" class="btn btn-outline-secondary btn-sm">−</button>
|
|
||||||
<button type="button" class="btn btn-outline-secondary btn-sm" tabindex="-1">2</button>
|
|
||||||
<button type="button" class="btn btn-outline-secondary btn-sm">+</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-flex align-items-center gap-2 flex-wrap">
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary">Edit</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-danger">Remove</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<script is:inline>
|
||||||
|
console.log('Setting up inventory tooltips');
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
console.log('Initializing tooltips');
|
||||||
|
htmx.process(document.getElementById('inventoryEntryList'));
|
||||||
|
console.log('Tooltips initialized');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -234,6 +234,8 @@ const facets = searchResults.results.slice(1).map((result: any) => {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<script define:vars={{ totalHits, filters, facets }} is:inline>
|
<script define:vars={{ totalHits, filters, facets }} is:inline>
|
||||||
|
import { c } from "@clerk/shared/index-Cx9VOot7";
|
||||||
|
|
||||||
|
|
||||||
// Filter the facet values to make things like Set easier to find
|
// Filter the facet values to make things like Set easier to find
|
||||||
const facetfilters = document.querySelectorAll('.facet-filter');
|
const facetfilters = document.querySelectorAll('.facet-filter');
|
||||||
@@ -260,7 +262,8 @@ const facets = searchResults.results.slice(1).map((result: any) => {
|
|||||||
document.getElementById('searchform').dispatchEvent(new Event('submit', {bubbles:true, cancelable:true}));
|
document.getElementById('searchform').dispatchEvent(new Event('submit', {bubbles:true, cancelable:true}));
|
||||||
}
|
}
|
||||||
document.getElementById('clear-filters').addEventListener('click', (e) => clearAllFilters(e));
|
document.getElementById('clear-filters').addEventListener('click', (e) => clearAllFilters(e));
|
||||||
document.getElementById('clear-all-filters').addEventListener('click', (e) => clearAllFilters(e));
|
const clearAllBtn = document.getElementById('clear-all-filters');
|
||||||
|
if (clearAllBtn) clearAllBtn.addEventListener('click', (e) => clearAllFilters(e));
|
||||||
|
|
||||||
// Remove single facet value
|
// Remove single facet value
|
||||||
for (const li of document.querySelectorAll('.remove-filter')) {
|
for (const li of document.querySelectorAll('.remove-filter')) {
|
||||||
|
|||||||
Reference in New Issue
Block a user