feat: add quantity support to totals, UI, and thread resolution

- totals.service: multiply weight/cost sums by quantity in category and global totals
- setup.service: multiply by quantity in getAllSetups SQL subqueries; expose quantity in getSetupWithItems item list
- thread.service: explicitly pass quantity: 1 when inserting resolved item
- ItemForm: add Quantity number input (min=1, default=1) after price field
- ItemCard: show ×N badge next to item name when quantity > 1
- CollectionView: pass quantity prop to ItemCard in both filtered and grouped views
- $setupId.tsx: pass quantity to ItemCard; multiply by quantity in client-side per-setup totals
- WeightSummaryCard: multiply by quantity in all chart and legend weight calculations
- useItems / useSetups: add quantity to ItemWithCategory / SetupItemWithCategory interfaces

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-03 18:04:27 +02:00
parent 923a0f66b0
commit 1a5e6a303e
10 changed files with 79 additions and 20 deletions

View File

@@ -53,13 +53,13 @@ function SetupDetailPage() {
);
}
// Compute totals from items
// Compute totals from items (multiply by quantity)
const totalWeight = setup.items.reduce(
(sum, item) => sum + (item.weightGrams ?? 0),
(sum, item) => sum + (item.weightGrams ?? 0) * (item.quantity ?? 1),
0,
);
const totalCost = setup.items.reduce(
(sum, item) => sum + (item.priceCents ?? 0),
(sum, item) => sum + (item.priceCents ?? 0) * (item.quantity ?? 1),
0,
);
const itemCount = setup.items.length;
@@ -207,11 +207,13 @@ function SetupDetailPage() {
{ items: categoryItems, categoryName, categoryIcon },
]) => {
const catWeight = categoryItems.reduce(
(sum, item) => sum + (item.weightGrams ?? 0),
(sum, item) =>
sum + (item.weightGrams ?? 0) * (item.quantity ?? 1),
0,
);
const catCost = categoryItems.reduce(
(sum, item) => sum + (item.priceCents ?? 0),
(sum, item) =>
sum + (item.priceCents ?? 0) * (item.quantity ?? 1),
0,
);
return (
@@ -232,6 +234,7 @@ function SetupDetailPage() {
name={item.name}
weightGrams={item.weightGrams}
priceCents={item.priceCents}
quantity={item.quantity}
categoryName={categoryName}
categoryIcon={categoryIcon}
imageFilename={item.imageFilename}