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:
2026-07-29 00:07:53 +02:00
parent 1cfbf1db49
commit 9d3261718f
8 changed files with 12 additions and 66 deletions
-3
View File
@@ -67,9 +67,6 @@ export function initCollectionFilter() {
case "total-desc": case "total-desc":
return (a: HTMLElement, b: HTMLElement) => return (a: HTMLElement, b: HTMLElement) =>
num(b, "total") - num(a, "total"); num(b, "total") - num(a, "total");
case "qty-desc":
return (a: HTMLElement, b: HTMLElement) =>
num(b, "qty") - num(a, "qty");
default: default:
// "Ajout récent" — original server-rendered order // "Ajout récent" — original server-rendered order
return (a: HTMLElement, b: HTMLElement) => return (a: HTMLElement, b: HTMLElement) =>
+4 -4
View File
@@ -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 * 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( export async function priceCollectionCards(
cards: MyCard[], cards: MyCard[],
@@ -36,8 +37,7 @@ export async function priceCollectionCards(
const priceKey = variantPriceMap[card.variant ?? ""] ?? "avg"; const priceKey = variantPriceMap[card.variant ?? ""] ?? "avg";
price = cardmarket[priceKey] ?? cardmarket.avg ?? 0; price = cardmarket[priceKey] ?? cardmarket.avg ?? 0;
} }
const quantity = card.quantity ?? 1; return { ...card, price, totalPrice: price };
return { ...card, price, totalPrice: price * quantity };
}), }),
); );
} }
-1
View File
@@ -32,7 +32,6 @@ export interface MyCard {
card_name: string; card_name: string;
card_image: string | null; card_image: string | null;
variant: string | null; variant: string | null;
quantity: number | null;
condition: string | null; condition: string | null;
notes: string | null; notes: string | null;
set_name: string | null; set_name: string | null;
-2
View File
@@ -15,7 +15,6 @@ export const POST: APIRoute = async ({ request, locals }) => {
card_name, card_name,
card_image, card_image,
variant, variant,
quantity,
condition, condition,
notes, notes,
set_name, set_name,
@@ -36,7 +35,6 @@ export const POST: APIRoute = async ({ request, locals }) => {
card_name, card_name,
card_image: card_image || null, card_image: card_image || null,
variant: variant || "Base", variant: variant || "Base",
quantity: Number(quantity) || 1,
condition: condition || null, condition: condition || null,
notes: notes || null, notes: notes || null,
set_name: set_name || null, set_name: set_name || null,
+3 -21
View File
@@ -53,19 +53,15 @@ const availableVariants = card.variants
const variantPrices: { label: string; price: number }[] = []; const variantPrices: { label: string; price: number }[] = [];
// Always include the base avg price (no variant suffix) // Always include the base avg price (0 when no Cardmarket data)
if (cardmarket?.avg != null) { variantPrices.push({ label: "Base", price: cardmarket?.avg ?? 0 });
variantPrices.push({ label: "Base", price: cardmarket.avg });
}
// Add prices for each available variant // Add prices for each available variant
for (const variant of availableVariants) { for (const variant of availableVariants) {
if (variant === "normal") continue; // normal uses the base avg, already added if (variant === "normal") continue; // normal uses the base avg, already added
const priceKey = variantPriceMap[variant]; const priceKey = variantPriceMap[variant];
const price = cardmarket?.[priceKey]; const price = cardmarket?.[priceKey] ?? 0;
if (price != null) {
variantPrices.push({ label: variantLabels[variant] ?? variant, price }); variantPrices.push({ label: variantLabels[variant] ?? variant, price });
}
} }
// Determine which tabs have content // Determine which tabs have content
@@ -527,19 +523,6 @@ const primaryColor = getPrimaryColor(typeNames);
</select> </select>
</div> </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"> <div role="group" class="field">
<label for="condition">État</label> <label for="condition">État</label>
<select <select
@@ -650,7 +633,6 @@ const primaryColor = getPrimaryColor(typeNames);
card_image: formData.get("card_image"), card_image: formData.get("card_image"),
set_name: formData.get("set_name"), set_name: formData.get("set_name"),
variant: formData.get("variant"), variant: formData.get("variant"),
quantity: Number(formData.get("quantity")),
condition: formData.get("condition"), condition: formData.get("condition"),
notes: formData.get("notes"), notes: formData.get("notes"),
}; };
+1 -9
View File
@@ -88,7 +88,7 @@ const myCards = (await directus!.request(
const cardsWithPrice = await priceCollectionCards(myCards); const cardsWithPrice = await priceCollectionCards(myCards);
const totalValue = cardsWithPrice.reduce((s, c) => s + c.totalPrice, 0); 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> <BaseLayout>
@@ -182,9 +182,6 @@ const totalCards = cardsWithPrice.reduce((s, c) => s + (c.quantity ?? 0), 0);
> >
{card.variant} {card.variant}
</span> </span>
<span class="font-semibold text-sm">
×{card.quantity}
</span>
</div> </div>
{card.condition && ( {card.condition && (
<span <span
@@ -204,11 +201,6 @@ const totalCards = cardsWithPrice.reduce((s, c) => s + (c.quantity ?? 0), 0);
<span class="font-bold text-base"> <span class="font-bold text-base">
{card.price.toFixed(2)} € {card.price.toFixed(2)} €
</span> </span>
{card.quantity > 1 && (
<span class="text-xs opacity-70">
= {card.totalPrice.toFixed(2)} €
</span>
)}
</div> </div>
</div> </div>
</a> </a>
+2 -2
View File
@@ -27,14 +27,14 @@ const myCards = (await directus!.request(
const cardsWithPrice = await priceCollectionCards(myCards); const cardsWithPrice = await priceCollectionCards(myCards);
// Insights // 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 totalValue = cardsWithPrice.reduce((s, c) => s + c.totalPrice, 0);
const bySet = new Map<string, { count: number; value: number }>(); const bySet = new Map<string, { count: number; value: number }>();
for (const c of cardsWithPrice) { for (const c of cardsWithPrice) {
const key = c.set_name || "Inconnu"; const key = c.set_name || "Inconnu";
const entry = bySet.get(key) ?? { count: 0, value: 0 }; const entry = bySet.get(key) ?? { count: 0, value: 0 };
entry.count += c.quantity; entry.count += 1;
entry.value += c.totalPrice; entry.value += c.totalPrice;
bySet.set(key, entry); bySet.set(key, entry);
} }
+1 -23
View File
@@ -29,10 +29,7 @@ const totalValue = cardsWithPrice.reduce(
(sum, card) => sum + card.totalPrice, (sum, card) => sum + card.totalPrice,
0, 0,
); );
const totalCards = cardsWithPrice.reduce( const totalCards = cardsWithPrice.length;
(sum, card) => sum + (card.quantity ?? 0),
0,
);
// Distinct values present in the collection, for the filter dropdowns // Distinct values present in the collection, for the filter dropdowns
const distinctSets = [ const distinctSets = [
@@ -161,7 +158,6 @@ const distinctConditions = [
<option value="total-desc"> <option value="total-desc">
Valeur totale ↓ Valeur totale ↓
</option> </option>
<option value="qty-desc">Quantité ↓</option>
</select> </select>
</label> </label>
<button type="button" id="cf-reset" class="pill"> <button type="button" id="cf-reset" class="pill">
@@ -244,7 +240,6 @@ const distinctConditions = [
data-condition={card.condition} data-condition={card.condition}
data-price={card.price} data-price={card.price}
data-total={card.totalPrice} data-total={card.totalPrice}
data-qty={card.quantity}
> >
<a <a
href={`/card/${card.card_id}`} href={`/card/${card.card_id}`}
@@ -278,9 +273,6 @@ const distinctConditions = [
<span class="badge" data-variant="secondary"> <span class="badge" data-variant="secondary">
{card.variant} {card.variant}
</span> </span>
<span class="font-semibold text-sm">
×{card.quantity}
</span>
</div> </div>
{card.condition && ( {card.condition && (
<span class="badge" data-variant={card.condition === "Neuf" ? "primary" : card.condition === "Joué" ? "destructive" : "outline"}> <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"> <span class="font-bold text-base">
{card.price.toFixed(2)} € {card.price.toFixed(2)} €
</span> </span>
{card.quantity > 1 && (
<span class="text-xs opacity-70">
= {card.totalPrice.toFixed(2)} €
</span>
)}
</div> </div>
</div> </div>
</a> </a>
@@ -327,9 +314,7 @@ const distinctConditions = [
<th>Set</th> <th>Set</th>
<th>Variant</th> <th>Variant</th>
<th>État</th> <th>État</th>
<th class="text-end">Qté</th>
<th class="text-end">Prix</th> <th class="text-end">Prix</th>
<th class="text-end">Total</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -341,7 +326,6 @@ const distinctConditions = [
data-condition={card.condition} data-condition={card.condition}
data-price={card.price} data-price={card.price}
data-total={card.totalPrice} data-total={card.totalPrice}
data-qty={card.quantity}
> >
<td> <td>
<a href={`/card/${card.card_id}`}> <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> <span class="badge" data-variant={card.condition === "Neuf" ? "primary" : card.condition === "Joué" ? "destructive" : "outline"}>{card.condition}</span>
)} )}
</td> </td>
<td class="text-end tabular-nums">
×{card.quantity}
</td>
<td class="text-end tabular-nums font-semibold"> <td class="text-end tabular-nums font-semibold">
{card.price.toFixed(2)} € {card.price.toFixed(2)} €
</td> </td>
<td class="text-end tabular-nums font-bold">
{card.totalPrice.toFixed(2)} €
</td>
</tr> </tr>
))} ))}
</tbody> </tbody>