CodingNic

Favorites Page

Build the Favorites Page

Favorites Page 15 min read

Build the Favorites Page

Build the Favorites Page

Add a favorites-only filter

Open lib/contacts.ts. Add favoritesOnly to ContactQuery, and one more
condition to getContacts:

typescript
export type ContactQuery = {
  q?: string;
  page?: number;
  favoritesOnly?: boolean;
};

Inside getContacts, alongside the existing if (opts.q) block:

typescript
if (opts.favoritesOnly) {
  conditions.push(`c.favorite = TRUE`);
}

Since conditions is just an array joined with AND, this combines
cleanly with search and pagination — you can search within favorites,
and page through the results, for free.

Build the page

Replace the placeholder in app/favorites/page.tsx:

tsx
import { getContacts, PAGE_SIZE } from "@/lib/contacts";
import ContactList from "@/components/ContactList";
import SearchBar from "@/components/SearchBar";
import Pagination from "@/components/Pagination";

export const dynamic = "force-dynamic";

export default async function FavoritesPage({
  searchParams,
}: {
  searchParams: { q?: string; page?: string };
}) {
  const q = searchParams.q || "";
  const page = Number(searchParams.page) || 1;
  const { contacts, total } = await getContacts({ q, page, favoritesOnly: true });

  return (
    <>
      <div className="page-heading">
        <h1>Favorites</h1>
        <div className="meta">{total} {total === 1 ? "contact" : "contacts"}</div>
      </div>
      <SearchBar action="/favorites" defaultValue={q} />
      <ContactList
        contacts={contacts}
        emptyTitle={q ? "No matches" : "No favorites yet"}
        emptyBody={q ? `No favorites match "${q}".` : "Star a contact to pin them here."}
      />
      <Pagination page={page} total={total} pageSize={PAGE_SIZE} basePath="/favorites" query={q} />
    </>
  );
}

This is nearly identical to app/page.tsx — same components, same
props — with two differences: favoritesOnly: true passed into
getContacts, and basePath/action pointing at /favorites instead of
/, so search and pagination links stay on this page.

Test it

Star a couple of contacts from their detail pages if you haven’t already,
then click “Favorites” in the nav. You should see only your starred
contacts, with search and pagination both still working, scoped to just
that filtered set.

Checkpoint

The Favorites page shows only favorited contacts, with its own working
search and pagination.