DEV Community

Cover image for Day 2: The Secret Gift List (Purchase Tracker) 🎁
Michael Amachree
Michael Amachree Subscriber

Posted on

Day 2: The Secret Gift List (Purchase Tracker) 🎁

It's Day 2 of the #12DaysOfSvelteApps! πŸŽ„

Yesterday, we managed the cost of the holidays with the Budget Tracker. Today, we're managing the chaos of the gifts themselves.

The App: Purchase Tracker

The Purchase Tracker is your digital shopping assistant. While generic note-taking apps are fine, they lack structure. This app treats every potential gift as an "Item" with properties like category, default currency, and unit measurements.

πŸ”— Try the App Live
πŸ’» View the Code

The "Use Case": The Anti-Spoiler List 🀫

We all have that one family member who snoops on the shared "To-Do" list or the fridge notepad.
Use the Purchase Tracker to create a "Gifts" category.

  • Name: The person you are buying for (or the item code name).
  • Description: The actual item detail (e.g., "Size M, Blue, from that one vintage store").
  • Privacy: Since the app functions essentially as a local database, your surprise plans remain on your device (or secured in your account).

Tech Spotlight: Optimistic UI ⚑

One of the best UX patterns we implemented here is Optimistic UI. When you create a new Item, we don't want the user to wait for the server to say "Okay." We want it to appear instantly.

In our Svelte component:

function handleLocalCreateItem(e: SubmitEvent) {
    e.preventDefault();
    // ... extract form data ...

    // 1. Update the local state IMMEDIATELY
    const newItem = addItem(name, category, description, unit, currency);

    // The UI updates instantly because 'items' is a reactive Svelte state
    // items.current = [...oldItems, newItem];

    toast.success('Item created successfully');
}
Enter fullscreen mode Exit fullscreen mode

If the user is logged in, we perform the server request in the background. If it fails, we roll back. But 99% of the time, the user experiences zero latency.

Dealing with Complex Lists

We used shadcn-svelte components to quickly scaffold a beautiful Table view.

<Table>
    <TableHeader>
        <TableRow>
            <TableHead>Name</TableHead>
            <TableHead>Category</TableHead>
            <!-- ... -->
        </TableRow>
    </TableHeader>
    <TableBody>
        {#each items.current as item (item.id)}
            <TableRow onclick={() => navigateToPurchases(item.id)}>
                <TableCell>{item.name}</TableCell>
                <TableCell>
                    <!-- Category Icon + Name lookup -->
                    {categories.find(c => c.id === item.category)?.name}
                </TableCell>
            </TableRow>
        {/each}
    </TableBody>
</Table>
Enter fullscreen mode Exit fullscreen mode

Using Svelte's {#each key} block (the (item.id) part) is crucial here. It ensures that when we delete or reorder items, the DOM updates efficiently without weird rendering artifactsβ€”a must-have for any list-heavy application.

Next Up

Now that we have a Budget and a Shopping List, we need to actually get things done. Join us tomorrow for Day 3.

Top comments (0)