Task Filters and Toasts
Introduction: Let the URL Drive the UI
Welcome back! 🙌 At this point, your Task Manager UI already feels like a real app. It has a dashboard shell, consistent task rows, reusable buttons, and pages that fetch live task data from the backend.
In this final unit, you’ll make the UI feel smarter by letting the URL control what the user sees. This is an important idea in modern web apps because the URL is not just an address bar detail — it can also act as part of your application state. When the URL changes, the UI can react to it, which makes views shareable, bookmarkable, and easier to understand.
There are three main improvements in this unit. First, you’ll build a proper Filtered Tasks view that reads a query param (completed=true|false), validates it, fetches the matching data, and renders results using your existing TaskRow component. Next, you’ll polish the stub routes so they feel more intentional, even though full CRUD is not implemented yet. Finally, you’ll add a lightweight toast notification system so even a temporary page can give the user friendly, app-like feedback.
Together, these changes make the UI feel more dynamic and more product-like without requiring any backend changes.
Previously…
In the previous unit, you extracted repeated markup into reusable components like TaskRow and Button, and you wired up navigation so /tasks/new and /tasks/[id] routes already exist. That gave the app a stronger internal structure and made the UI more consistent across pages.
Now you’ll build on top of that structure with URL-driven filtering, stronger product-style stub pages, and a toast system for small but meaningful feedback. These are the kinds of additions that make an app feel more polished, even before all of its features are complete.
And as always, one rule remains unchanged: the backend lives under src/app/api/** and is read-only for this course unit. You should not modify it. Your job is to consume the existing backend cleanly and build the frontend around the API contract it already provides.
Keeping Frontend and Backend Separate
Your UI consumes endpoints that already exist. In this unit, you’ll specifically rely on: GET /api/tasks/filter?completed=true|false → { data: Task[] }
This matters for two reasons. First, the backend expects exact string values: "true" or "false". That means your frontend should not invent alternate values like "yes", "0", or booleans in the URL. Second, the backend wraps its returned task array inside an object, so you must read tasks from json.data instead of assuming the response itself is the array.
If your UI validates correctly and fetches correctly, the same filter page will continue to work no matter how many tasks exist or how the list changes over time. That is one of the benefits of keeping frontend and backend responsibilities cleanly separated: each side stays predictable.
