feat(cospend): edit name and amount in list edit modal
Long-press modal on /cospend/list now lets you change the item's name and quantity (e.g. "500g", "3x") alongside category and icon. The quantity is re-prepended to the name so the existing parser keeps picking it up.
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "homepage",
|
||||
"version": "1.42.1",
|
||||
"version": "1.43.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -178,6 +178,9 @@ const translations: Translations = {
|
||||
search_icon: { en: 'Search icon...', de: 'Icon suchen...' },
|
||||
save: { en: 'Save', de: 'Speichern' },
|
||||
saving: { en: 'Saving...', de: 'Speichern...' },
|
||||
edit_name: { en: 'Name', de: 'Name' },
|
||||
edit_qty: { en: 'Amount', de: 'Menge' },
|
||||
edit_qty_ph: { en: 'e.g. 3x, 500g, 1L', de: 'z.B. 3x, 500g, 1L' },
|
||||
|
||||
// EnhancedBalance
|
||||
your_balance: { en: 'Your Balance', de: 'Dein Saldo' },
|
||||
|
||||
@@ -219,6 +219,11 @@ export function createShoppingSync() {
|
||||
debouncedPush();
|
||||
}
|
||||
|
||||
function updateItem(id: string, patch: Partial<Omit<ShoppingItem, 'id'>>) {
|
||||
items = items.map(item => item.id === id ? { ...item, ...patch } : item);
|
||||
debouncedPush();
|
||||
}
|
||||
|
||||
return {
|
||||
get items() { return items; },
|
||||
get status() { return status; },
|
||||
@@ -232,6 +237,7 @@ export function createShoppingSync() {
|
||||
removeItem,
|
||||
clearChecked,
|
||||
updateItemCategory,
|
||||
updateItem,
|
||||
disconnect
|
||||
};
|
||||
}
|
||||
|
||||
@@ -205,6 +205,8 @@
|
||||
let longPressTimer = $state(null);
|
||||
/** @type {import('$lib/js/shoppingSync.svelte').ShoppingItem | null} */
|
||||
let editingItem = $state(null);
|
||||
let editName = $state('');
|
||||
let editQty = $state('');
|
||||
let editCategory = $state('');
|
||||
let editIcon = $state('');
|
||||
let iconSearch = $state('');
|
||||
@@ -238,6 +240,9 @@
|
||||
function startLongPress(item) {
|
||||
longPressTimer = window.setTimeout(() => {
|
||||
editingItem = item;
|
||||
const parsed = parseQuantity(item.name);
|
||||
editName = parsed.name;
|
||||
editQty = parsed.qty || '';
|
||||
editCategory = item.category;
|
||||
editIcon = item.icon || '';
|
||||
iconSearch = '';
|
||||
@@ -355,14 +360,21 @@
|
||||
async function saveEdit() {
|
||||
if (!editingItem) return;
|
||||
editSaving = true;
|
||||
const cleanName = parseQuantity(editingItem.name).name;
|
||||
const trimmedName = editName.trim();
|
||||
const trimmedQty = editQty.trim();
|
||||
if (!trimmedName) { editSaving = false; return; }
|
||||
const newRawName = trimmedQty ? `${trimmedQty} ${trimmedName}` : trimmedName;
|
||||
try {
|
||||
await fetch(sync.apiUrl('/api/cospend/list/categorize/override'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name: cleanName, category: editCategory, icon: editIcon || null })
|
||||
body: JSON.stringify({ name: trimmedName, category: editCategory, icon: editIcon || null })
|
||||
});
|
||||
sync.updateItem(editingItem.id, {
|
||||
name: newRawName,
|
||||
category: editCategory,
|
||||
icon: editIcon || null
|
||||
});
|
||||
sync.updateItemCategory(editingItem.id, editCategory, editIcon || null);
|
||||
closeEdit();
|
||||
} catch (err) {
|
||||
console.error('[shopping] Save override error:', err);
|
||||
@@ -482,6 +494,19 @@
|
||||
<div class="edit-modal" onclick={(e) => e.stopPropagation()}>
|
||||
<h3>{parseQuantity(editingItem.name).name}</h3>
|
||||
|
||||
<div class="name-qty-row">
|
||||
<div class="field name-field">
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="edit-label">{t('edit_name', lang)}</label>
|
||||
<input class="edit-input" type="text" bind:value={editName} />
|
||||
</div>
|
||||
<div class="field qty-field">
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="edit-label">{t('edit_qty', lang)}</label>
|
||||
<input class="edit-input" type="text" bind:value={editQty} placeholder={t('edit_qty_ph', lang)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="edit-label">{t('kategorie', lang)}</label>
|
||||
<div class="category-picker">
|
||||
@@ -934,6 +959,29 @@
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.name-qty-row {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.field { display: flex; flex-direction: column; }
|
||||
.name-field { flex: 2; }
|
||||
.qty-field { flex: 1; }
|
||||
.edit-input {
|
||||
padding: 0.5rem 0.65rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 8px;
|
||||
background: var(--color-bg-tertiary);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 0.9rem;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.edit-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--nord10);
|
||||
}
|
||||
|
||||
.category-picker {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
Reference in New Issue
Block a user