Skip to content

[Frontend] Implement Article Search UI and Navbar Integration #57

Description

@xandreiAThome

1. Summary

Implement the user-facing search functionality across the application. This involves wiring up the desktop and mobile search inputs in the Navbar to redirect users to a dedicated /search page. The page will reactively fetch and display matching articles using TanStack Query, and allow users to refine results by category and sort options.

2. Blocker

  • Schema Validation: Extend articleSearchQuerySchema in src/features/article/types/index.ts with optional category (positive integer) and sort ('newest' | 'oldest' | 'popular', default 'newest') parameters.
  • API Endpoint: Update GET /api/articles/search in src/app/api/articles/search/route.ts to parse, validate, and forward category and sort query parameters.
  • Database Service: Update searchArticles in src/features/article/services/service.ts to pass query.category and query.sort to listArticlesWithCount, filtering results by category and applying the specified sort order.

3. Scope

  • Shared Query Hook:
    • src/features/article/queries/useSearchArticles.ts — extend to accept category and sort options
  • Navigation & Layout Components:
    • src/components/organisms/Navbar.tsx — desktop and mobile search inputs
  • New Search Feature & Page:
    • src/app/search/page.tsx — new App Router page wrapper (with <Suspense> boundary)
    • src/features/search/ — new feature directory for search-specific UI
  • Existing Shared Components (reused, not modified):
    • ArticleList component for rendering results
    • Pagination component
    • Category list hook (useCategoryList)

4. Deliverables

  • Navbar Search Integration: Controlled search inputs that navigate to /search?q=<query> on submission (Enter or click). Mobile input in slide-out nav auto-closes the sheet on route change.
  • Search Results Page (/search):
    • Dynamic page wrapped in a <Suspense> boundary for useSearchParams() compliance
    • Skeleton loaders for fetching state
    • "No results found for '{query}'" empty state layout
  • Filter & Sort Controls:
    • Category filter selector (horizontal scrollable pills using useCategoryList)
    • Sort dropdown (Newest / Oldest / Popular)
    • Changes immediately update URL params and reset page to 1
  • Search Header: Displays query phrase and matched results count
  • Pagination: Standard pagination controls tied to &page=X URL param
  • Input Validation: Client-side enforcement of q.trim().length >= 3 with user feedback

5. Implementation Notes

  • State & URL Sync: Treat browser URL search params (q, category, sort, page) as the single source of truth. Enables shareable URLs and native browser navigation.
  • Architectural Pattern: Container/Presentational. Keep params and data-fetching in SearchContainer.tsx, delegate visual layout to presentational components (e.g. ArticleList).
  • Hook Extension: Update useSearchArticles to accept category and sort options and include them in the queryKey array for proper cache invalidation.
  • Schema Alignment: Ensure client param names match the backend schema exactly (category as number, sort as enum).

6. Acceptance Criteria

  • Typing a search query in desktop or mobile navbar and pressing Enter navigates to /search?q={query}.
  • Mobile search in the slide-out nav sheet auto-closes the sheet on route change.
  • /search extracts q, category, sort, page from URL params and fetches matching articles.
  • Submitting a query <3 characters shows a warning and prevents submission.
  • Selecting category filters or changing sort immediately updates URL params and triggers a loading skeleton.
  • Empty results display "No results found for '{query}'".
  • Pagination controls are visible and functional when multiple pages exist.
  • Code compiles without TypeScript errors (npm run build).
  • No ESLint or Prettier violations (npm run lint / npm run format).

7. Tasks

Phase 1: Navbar Search Inputs

  • Bind controlled state to search inputs in Navbar (desktop and mobile sections).
  • On submission (Enter or search icon click), redirect to /search?q=<query>.
  • Ensure mobile nav sheet closes when search is triggered on mobile.
  • Prevent submission if q.trim().length < 3, show inline warning.

Phase 2: Hook & Page Scaffold

  • Update useSearchArticles.ts to accept category and sort options; add them to queryKey.
  • Scaffold page at src/app/search/page.tsx with <Suspense> boundary.
  • Create SearchContainer.tsx in src/features/search/containers/.
  • Read query params using useSearchParams and invoke useSearchArticles(q, { category, sort, page }).
  • Render search results using existing ArticleList component.

Phase 3: Filters, Sort & Pagination

  • Implement skeleton loaders inside SearchContainer for isLoading state.
  • Add category filter pills (using useCategoryList) to the top of the search page.
  • Add sort dropdown (Newest / Oldest / Popular) to the top-right.
  • Sync filter/sort changes to URL params (update category, sort, reset page to 1).
  • Add SearchHeader showing query string and results count.
  • Implement empty state: "No results found for '{query}'".
  • Implement pagination UI tied to &page=X URL param.

Phase 4: Validation & Quality

  • Write unit tests for Navbar search interaction and input validation.
  • Run npm run format and npm run lint.
  • Run npm run build to confirm the build typechecks successfully.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions