refactor: simplify ItemForm API using events instead of callback props

This commit is contained in:
Rasmus Q
2026-03-16 14:20:50 +00:00
parent d63535ad1b
commit 563ee5699b
2 changed files with 34 additions and 36 deletions

View File

@@ -11,16 +11,19 @@
import { languageStore } from '$lib/stores/language.svelte';
import ThemeCard from '$lib/components/themes/ThemeCard.svelte';
import { getCardStyle } from '$lib/utils/colors';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher<{
success: void;
cancel: void;
colorChange: { itemId: string; color: string };
positionChange: { itemId: string; newPosition: number };
}>();
interface Props {
item?: Item | null;
mode: 'add' | 'edit';
onSuccess?: () => void;
onCancel?: () => void;
onColorChange?: (itemId: string, color: string) => void;
currentPosition?: number;
totalItems?: number;
onPositionChange?: (newPosition: number) => void;
itemCount?: number;
wishlistColor?: string | null;
wishlistTheme?: string | null;
}
@@ -28,12 +31,7 @@
let {
item = null,
mode,
onSuccess,
onCancel,
onColorChange,
currentPosition = 1,
totalItems = 1,
onPositionChange,
itemCount = 1,
wishlistColor = null,
wishlistTheme = null
}: Props = $props();
@@ -47,6 +45,7 @@
let linkUrl = $state(item?.link || '');
let imageUrl = $state(item?.imageUrl || '');
let color = $state<string | null>(item?.color || null);
let position = $state(item?.order ? Number(item.order) + 1 : 1);
let scrapedImages = $state<string[]>([]);
let isLoadingImages = $state(false);
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
@@ -97,7 +96,13 @@
function handleColorChange() {
if (isEdit && item) {
onColorChange?.(item.id, color || '');
dispatch('colorChange', { itemId: item.id, color: color || '' });
}
}
function handlePositionChange() {
if (isEdit && item) {
dispatch('positionChange', { itemId: item.id, newPosition: position });
}
}
@@ -121,7 +126,7 @@
use:enhance={() => {
return async ({ update }) => {
await update({ reset: false });
onSuccess?.();
dispatch('success');
};
}}
class="space-y-4"
@@ -222,20 +227,16 @@
<Label for="position">{t.form.position}</Label>
<Input
id="position"
name="position"
type="number"
min="1"
max={totalItems}
value={currentPosition}
onchange={(e) => {
const newPos = parseInt((e.target as HTMLInputElement).value);
if (newPos >= 1 && newPos <= totalItems) {
onPositionChange?.(newPos);
}
}}
max={itemCount}
bind:value={position}
onchange={handlePositionChange}
placeholder="1"
/>
<p class="text-sm text-muted-foreground">
Choose where this item appears in your wishlist (1 = top, {totalItems} = bottom)
Choose where this item appears in your wishlist (1 = top, {itemCount} = bottom)
</p>
</div>
{/if}
@@ -243,8 +244,8 @@
<div class="flex gap-2">
<Button type="submit" class="flex-1 md:flex-none">{submitLabel}</Button>
{#if onCancel}
<Button type="button" variant="outline" class="flex-1 md:flex-none" onclick={onCancel}>
{#if isEdit}
<Button type="button" variant="outline" class="flex-1 md:flex-none" onclick={() => dispatch('cancel')}>
{t.form.cancel}
</Button>
{/if}

View File

@@ -88,10 +88,8 @@
}
}
async function handlePositionChange(newPosition: number) {
if (!editingItem) return;
const currentIndex = items.findIndex((item) => item.id === editingItem.id);
async function handlePositionChange(itemId: string, newPosition: number) {
const currentIndex = items.findIndex((item) => item.id === itemId);
if (currentIndex === -1) return;
const newIndex = newPosition - 1; // Convert to 0-based index
@@ -150,7 +148,7 @@
<div bind:this={addFormElement}>
<ItemForm
mode="add"
onSuccess={handleItemAdded}
on:success={handleItemAdded}
wishlistColor={currentColor}
wishlistTheme={currentTheme}
/>
@@ -162,12 +160,11 @@
<ItemForm
mode="edit"
item={editingItem}
onSuccess={handleItemUpdated}
onCancel={cancelEditing}
onColorChange={handleColorChange}
currentPosition={items.findIndex((item) => item.id === editingItem.id) + 1}
totalItems={items.length}
onPositionChange={handlePositionChange}
itemCount={items.length}
on:success={handleItemUpdated}
on:cancel={cancelEditing}
on:colorChange={(e) => handleColorChange(e.detail.itemId, e.detail.color)}
on:positionChange={(e) => handlePositionChange(e.detail.itemId, e.detail.newPosition)}
wishlistColor={currentColor}
wishlistTheme={currentTheme}
/>