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:
@@ -13,6 +13,7 @@ interface FormData {
|
||||
name: string;
|
||||
weightGrams: string;
|
||||
priceDollars: string;
|
||||
quantity: number;
|
||||
categoryId: number;
|
||||
notes: string;
|
||||
productUrl: string;
|
||||
@@ -23,6 +24,7 @@ const INITIAL_FORM: FormData = {
|
||||
name: "",
|
||||
weightGrams: "",
|
||||
priceDollars: "",
|
||||
quantity: 1,
|
||||
categoryId: 1,
|
||||
notes: "",
|
||||
productUrl: "",
|
||||
@@ -49,6 +51,7 @@ export function ItemForm({ mode, itemId }: ItemFormProps) {
|
||||
weightGrams: item.weightGrams != null ? String(item.weightGrams) : "",
|
||||
priceDollars:
|
||||
item.priceCents != null ? (item.priceCents / 100).toFixed(2) : "",
|
||||
quantity: item.quantity ?? 1,
|
||||
categoryId: item.categoryId,
|
||||
notes: item.notes ?? "",
|
||||
productUrl: item.productUrl ?? "",
|
||||
@@ -98,6 +101,7 @@ export function ItemForm({ mode, itemId }: ItemFormProps) {
|
||||
priceCents: form.priceDollars
|
||||
? Math.round(Number(form.priceDollars) * 100)
|
||||
: undefined,
|
||||
quantity: form.quantity,
|
||||
categoryId: form.categoryId,
|
||||
notes: form.notes.trim() || undefined,
|
||||
productUrl: form.productUrl.trim() || undefined,
|
||||
@@ -202,6 +206,30 @@ export function ItemForm({ mode, itemId }: ItemFormProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Quantity */}
|
||||
<div>
|
||||
<label
|
||||
htmlFor="item-quantity"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Quantity
|
||||
</label>
|
||||
<input
|
||||
id="item-quantity"
|
||||
type="number"
|
||||
min="1"
|
||||
step="1"
|
||||
value={form.quantity}
|
||||
onChange={(e) =>
|
||||
setForm((f) => ({
|
||||
...f,
|
||||
quantity: Math.max(1, Number(e.target.value) || 1),
|
||||
}))
|
||||
}
|
||||
className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-gray-400 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Category */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
|
||||
Reference in New Issue
Block a user