feat(fase-5.10.0): drop shopping_items.unit column
The unit field had no edit path under the redesign (only name + qty
remain in the row; the double-tap overlay is name-only). Users can encode
the unit inside the name when it matters — e.g. "Milk 1L", "Eggs 1 doz".
Changes
supabase/migrations/011_drop_shopping_items_unit.sql — DROP COLUMN
supabase/seed.sql — unit values folded into names where relevant
supabase/tests/002_item_frequency_trigger.sql — remove unit from INSERT
packages/types — remove unit from ShoppingItem Row/Insert/Update
apps/web/src/lib/stores/lists.ts — addItem/updateItem signatures
apps/web/src/routes/(app)/lists/[id]/+page.svelte — purge newUnit /
editUnit state + inputs + display
apps/web/src/routes/(app)/lists/[id]/session/+page.svelte — simplify
quantity-only render
apps/web/messages/{en,es}.json — remove list_unit_label
Verification
just test-db → 34 pgTAP green
just test-integration → 140 + 2 skipped
just test-unit → 11 green
just test-e2e → 39 + 2 skipped
The generated search tsvector on shopping_items.search already indexes
only `name`, so full-text search coverage is unchanged.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,7 +49,6 @@
|
||||
// Add-item form
|
||||
let newName = $state('');
|
||||
let newQty = $state<number | null>(null);
|
||||
let newUnit = $state('');
|
||||
let nameInput: HTMLInputElement | undefined = $state();
|
||||
|
||||
// Suggestions
|
||||
@@ -60,7 +59,6 @@
|
||||
let editingId = $state<string | null>(null);
|
||||
let editName = $state('');
|
||||
let editQty = $state<number | null>(null);
|
||||
let editUnit = $state('');
|
||||
|
||||
// Swipe-to-delete (touch only)
|
||||
let swipeOffsets = $state<Record<string, number>>({});
|
||||
@@ -169,7 +167,6 @@
|
||||
list_id: listId,
|
||||
name,
|
||||
quantity: newQty,
|
||||
unit: newUnit.trim() || null,
|
||||
is_checked: false,
|
||||
checked_by: null,
|
||||
checked_at: null,
|
||||
@@ -188,14 +185,12 @@
|
||||
items = [...items, optimistic];
|
||||
newName = '';
|
||||
newQty = null;
|
||||
newUnit = '';
|
||||
nameInput?.focus();
|
||||
|
||||
const real = await addItem(
|
||||
listId,
|
||||
name,
|
||||
newQty,
|
||||
optimistic.unit,
|
||||
$currentUser.id,
|
||||
sortOrder,
|
||||
tempId
|
||||
@@ -221,7 +216,6 @@
|
||||
list_id: listId,
|
||||
name,
|
||||
quantity: newQty,
|
||||
unit: optimistic.unit,
|
||||
sort_order: sortOrder,
|
||||
created_by: $currentUser.id
|
||||
}
|
||||
@@ -268,7 +262,6 @@
|
||||
editingId = item.id;
|
||||
editName = item.name;
|
||||
editQty = item.quantity;
|
||||
editUnit = item.unit ?? '';
|
||||
}
|
||||
|
||||
async function commitEdit(item: ShoppingItem) {
|
||||
@@ -276,18 +269,12 @@
|
||||
editingId = null;
|
||||
const name = editName.trim();
|
||||
if (!name) return;
|
||||
if (name === item.name && editQty === item.quantity && (editUnit || null) === item.unit) return;
|
||||
if (name === item.name && editQty === item.quantity) return;
|
||||
|
||||
items = items.map((i) =>
|
||||
i.id === item.id
|
||||
? { ...i, name, quantity: editQty, unit: editUnit.trim() || null }
|
||||
: i
|
||||
i.id === item.id ? { ...i, name, quantity: editQty } : i
|
||||
);
|
||||
await updateItem(item.id, {
|
||||
name,
|
||||
quantity: editQty,
|
||||
unit: editUnit.trim() || null
|
||||
});
|
||||
await updateItem(item.id, { name, quantity: editQty });
|
||||
}
|
||||
|
||||
function handleEditKeydown(e: KeyboardEvent, item: ShoppingItem) {
|
||||
@@ -531,15 +518,6 @@
|
||||
class="w-14 bg-transparent text-sm text-text-secondary outline-none
|
||||
border-b border-slate-300 dark:border-slate-600 pb-0.5 text-right"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={editUnit}
|
||||
onblur={() => commitEdit(item)}
|
||||
onkeydown={(e) => handleEditKeydown(e, item)}
|
||||
placeholder={m.list_unit_label()}
|
||||
class="w-14 bg-transparent text-sm text-text-secondary outline-none
|
||||
border-b border-slate-300 dark:border-slate-600 pb-0.5"
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Item display -->
|
||||
@@ -550,9 +528,6 @@
|
||||
<span class="block truncate text-sm text-slate-800 dark:text-slate-200">
|
||||
{item.name}
|
||||
</span>
|
||||
{#if item.unit}
|
||||
<span class="text-[12px] text-text-muted">{item.unit}</span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<!-- Quantity stepper -->
|
||||
@@ -662,16 +637,9 @@
|
||||
type="number"
|
||||
min="1"
|
||||
placeholder={m.list_qty_label()}
|
||||
class="w-12 bg-transparent text-sm text-text-secondary placeholder:text-text-muted
|
||||
outline-none text-right"
|
||||
/>
|
||||
<input
|
||||
bind:value={newUnit}
|
||||
type="text"
|
||||
placeholder={m.list_unit_label()}
|
||||
onkeydown={handleAddKeydown}
|
||||
class="w-12 bg-transparent text-sm text-text-secondary placeholder:text-text-muted
|
||||
outline-none"
|
||||
outline-none text-right"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
|
||||
@@ -134,10 +134,8 @@
|
||||
></button>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="truncate text-base font-medium">{item.name}</p>
|
||||
{#if item.quantity || item.unit}
|
||||
<p class="text-sm text-text-muted">
|
||||
{item.quantity ?? ''}{item.unit ? ' ' + item.unit : ''}
|
||||
</p>
|
||||
{#if item.quantity}
|
||||
<p class="text-sm text-text-muted">{item.quantity}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
Reference in New Issue
Block a user