Remove quantity field; normalize missing prices to 0,00 €
Each collection row is a unique card (own condition/notes), so quantity was noise: dropped the field in Directus and removed it from the add dialog, collection/grid/table views, dashboard stats and sort options. Cards without Cardmarket data now consistently show 0,00 € (base price row is always displayed on the card page).
This commit is contained in:
@@ -67,9 +67,6 @@ export function initCollectionFilter() {
|
||||
case "total-desc":
|
||||
return (a: HTMLElement, b: HTMLElement) =>
|
||||
num(b, "total") - num(a, "total");
|
||||
case "qty-desc":
|
||||
return (a: HTMLElement, b: HTMLElement) =>
|
||||
num(b, "qty") - num(a, "qty");
|
||||
default:
|
||||
// "Ajout récent" — original server-rendered order
|
||||
return (a: HTMLElement, b: HTMLElement) =>
|
||||
|
||||
@@ -20,9 +20,10 @@ export const variantPriceMap: Record<string, string> = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve the Cardmarket unit price and line total for each collection card.
|
||||
* Resolve the Cardmarket unit price for each collection card.
|
||||
* Card details come from the 24h in-memory cache, so repeated cards and
|
||||
* repeated page loads don't hit the TCGdex API again.
|
||||
* repeated page loads don't hit the TCGdex API again. Cards without a
|
||||
* Cardmarket price get 0 for consistent display (0,00 €).
|
||||
*/
|
||||
export async function priceCollectionCards(
|
||||
cards: MyCard[],
|
||||
@@ -36,8 +37,7 @@ export async function priceCollectionCards(
|
||||
const priceKey = variantPriceMap[card.variant ?? ""] ?? "avg";
|
||||
price = cardmarket[priceKey] ?? cardmarket.avg ?? 0;
|
||||
}
|
||||
const quantity = card.quantity ?? 1;
|
||||
return { ...card, price, totalPrice: price * quantity };
|
||||
return { ...card, price, totalPrice: price };
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ export interface MyCard {
|
||||
card_name: string;
|
||||
card_image: string | null;
|
||||
variant: string | null;
|
||||
quantity: number | null;
|
||||
condition: string | null;
|
||||
notes: string | null;
|
||||
set_name: string | null;
|
||||
|
||||
@@ -15,7 +15,6 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
||||
card_name,
|
||||
card_image,
|
||||
variant,
|
||||
quantity,
|
||||
condition,
|
||||
notes,
|
||||
set_name,
|
||||
@@ -36,7 +35,6 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
||||
card_name,
|
||||
card_image: card_image || null,
|
||||
variant: variant || "Base",
|
||||
quantity: Number(quantity) || 1,
|
||||
condition: condition || null,
|
||||
notes: notes || null,
|
||||
set_name: set_name || null,
|
||||
|
||||
@@ -53,19 +53,15 @@ const availableVariants = card.variants
|
||||
|
||||
const variantPrices: { label: string; price: number }[] = [];
|
||||
|
||||
// Always include the base avg price (no variant suffix)
|
||||
if (cardmarket?.avg != null) {
|
||||
variantPrices.push({ label: "Base", price: cardmarket.avg });
|
||||
}
|
||||
// Always include the base avg price (0 when no Cardmarket data)
|
||||
variantPrices.push({ label: "Base", price: cardmarket?.avg ?? 0 });
|
||||
|
||||
// Add prices for each available variant
|
||||
for (const variant of availableVariants) {
|
||||
if (variant === "normal") continue; // normal uses the base avg, already added
|
||||
const priceKey = variantPriceMap[variant];
|
||||
const price = cardmarket?.[priceKey];
|
||||
if (price != null) {
|
||||
variantPrices.push({ label: variantLabels[variant] ?? variant, price });
|
||||
}
|
||||
const price = cardmarket?.[priceKey] ?? 0;
|
||||
variantPrices.push({ label: variantLabels[variant] ?? variant, price });
|
||||
}
|
||||
|
||||
// Determine which tabs have content
|
||||
@@ -527,19 +523,6 @@ const primaryColor = getPrimaryColor(typeNames);
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div role="group" class="field">
|
||||
<label for="quantity">Quantité</label>
|
||||
<input
|
||||
type="number"
|
||||
name="quantity"
|
||||
id="quantity"
|
||||
class="input"
|
||||
value="1"
|
||||
min="1"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div role="group" class="field">
|
||||
<label for="condition">État</label>
|
||||
<select
|
||||
@@ -650,7 +633,6 @@ const primaryColor = getPrimaryColor(typeNames);
|
||||
card_image: formData.get("card_image"),
|
||||
set_name: formData.get("set_name"),
|
||||
variant: formData.get("variant"),
|
||||
quantity: Number(formData.get("quantity")),
|
||||
condition: formData.get("condition"),
|
||||
notes: formData.get("notes"),
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ const myCards = (await directus!.request(
|
||||
const cardsWithPrice = await priceCollectionCards(myCards);
|
||||
|
||||
const totalValue = cardsWithPrice.reduce((s, c) => s + c.totalPrice, 0);
|
||||
const totalCards = cardsWithPrice.reduce((s, c) => s + (c.quantity ?? 0), 0);
|
||||
const totalCards = cardsWithPrice.length;
|
||||
---
|
||||
|
||||
<BaseLayout>
|
||||
@@ -182,9 +182,6 @@ const totalCards = cardsWithPrice.reduce((s, c) => s + (c.quantity ?? 0), 0);
|
||||
>
|
||||
{card.variant}
|
||||
</span>
|
||||
<span class="font-semibold text-sm">
|
||||
×{card.quantity}
|
||||
</span>
|
||||
</div>
|
||||
{card.condition && (
|
||||
<span
|
||||
@@ -204,11 +201,6 @@ const totalCards = cardsWithPrice.reduce((s, c) => s + (c.quantity ?? 0), 0);
|
||||
<span class="font-bold text-base">
|
||||
{card.price.toFixed(2)} €
|
||||
</span>
|
||||
{card.quantity > 1 && (
|
||||
<span class="text-xs opacity-70">
|
||||
= {card.totalPrice.toFixed(2)} €
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@@ -27,14 +27,14 @@ const myCards = (await directus!.request(
|
||||
const cardsWithPrice = await priceCollectionCards(myCards);
|
||||
|
||||
// Insights
|
||||
const totalCards = cardsWithPrice.reduce((s, c) => s + (c.quantity ?? 0), 0);
|
||||
const totalCards = cardsWithPrice.length;
|
||||
const totalValue = cardsWithPrice.reduce((s, c) => s + c.totalPrice, 0);
|
||||
|
||||
const bySet = new Map<string, { count: number; value: number }>();
|
||||
for (const c of cardsWithPrice) {
|
||||
const key = c.set_name || "Inconnu";
|
||||
const entry = bySet.get(key) ?? { count: 0, value: 0 };
|
||||
entry.count += c.quantity;
|
||||
entry.count += 1;
|
||||
entry.value += c.totalPrice;
|
||||
bySet.set(key, entry);
|
||||
}
|
||||
|
||||
+1
-23
@@ -29,10 +29,7 @@ const totalValue = cardsWithPrice.reduce(
|
||||
(sum, card) => sum + card.totalPrice,
|
||||
0,
|
||||
);
|
||||
const totalCards = cardsWithPrice.reduce(
|
||||
(sum, card) => sum + (card.quantity ?? 0),
|
||||
0,
|
||||
);
|
||||
const totalCards = cardsWithPrice.length;
|
||||
|
||||
// Distinct values present in the collection, for the filter dropdowns
|
||||
const distinctSets = [
|
||||
@@ -161,7 +158,6 @@ const distinctConditions = [
|
||||
<option value="total-desc">
|
||||
Valeur totale ↓
|
||||
</option>
|
||||
<option value="qty-desc">Quantité ↓</option>
|
||||
</select>
|
||||
</label>
|
||||
<button type="button" id="cf-reset" class="pill">
|
||||
@@ -244,7 +240,6 @@ const distinctConditions = [
|
||||
data-condition={card.condition}
|
||||
data-price={card.price}
|
||||
data-total={card.totalPrice}
|
||||
data-qty={card.quantity}
|
||||
>
|
||||
<a
|
||||
href={`/card/${card.card_id}`}
|
||||
@@ -278,9 +273,6 @@ const distinctConditions = [
|
||||
<span class="badge" data-variant="secondary">
|
||||
{card.variant}
|
||||
</span>
|
||||
<span class="font-semibold text-sm">
|
||||
×{card.quantity}
|
||||
</span>
|
||||
</div>
|
||||
{card.condition && (
|
||||
<span class="badge" data-variant={card.condition === "Neuf" ? "primary" : card.condition === "Joué" ? "destructive" : "outline"}>
|
||||
@@ -291,11 +283,6 @@ const distinctConditions = [
|
||||
<span class="font-bold text-base">
|
||||
{card.price.toFixed(2)} €
|
||||
</span>
|
||||
{card.quantity > 1 && (
|
||||
<span class="text-xs opacity-70">
|
||||
= {card.totalPrice.toFixed(2)} €
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@@ -327,9 +314,7 @@ const distinctConditions = [
|
||||
<th>Set</th>
|
||||
<th>Variant</th>
|
||||
<th>État</th>
|
||||
<th class="text-end">Qté</th>
|
||||
<th class="text-end">Prix</th>
|
||||
<th class="text-end">Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -341,7 +326,6 @@ const distinctConditions = [
|
||||
data-condition={card.condition}
|
||||
data-price={card.price}
|
||||
data-total={card.totalPrice}
|
||||
data-qty={card.quantity}
|
||||
>
|
||||
<td>
|
||||
<a href={`/card/${card.card_id}`}>
|
||||
@@ -379,15 +363,9 @@ const distinctConditions = [
|
||||
<span class="badge" data-variant={card.condition === "Neuf" ? "primary" : card.condition === "Joué" ? "destructive" : "outline"}>{card.condition}</span>
|
||||
)}
|
||||
</td>
|
||||
<td class="text-end tabular-nums">
|
||||
×{card.quantity}
|
||||
</td>
|
||||
<td class="text-end tabular-nums font-semibold">
|
||||
{card.price.toFixed(2)} €
|
||||
</td>
|
||||
<td class="text-end tabular-nums font-bold">
|
||||
{card.totalPrice.toFixed(2)} €
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
||||
Reference in New Issue
Block a user