FTS5 prefix matching misses mid-word substrings (e.g. "ebook" in "notebook"). When FTS5 returns zero results, fall back to LIKE query on title and category with proper wildcard escaping. 4 new tests, 757 total. Also marks completed plan files (search, admin-redesign, setup-wizard, products-context) with correct status. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
62 lines
2.6 KiB
Markdown
62 lines
2.6 KiB
Markdown
# Plan: Implement product search in search modal
|
|
|
|
Status: Complete (037cd16, 57c3ba0)
|
|
|
|
## Overview
|
|
|
|
The search modal UI shell exists but has zero functionality — no event bindings, no backend search, no results rendering. This plan adds live search across all products.
|
|
|
|
## Approach
|
|
|
|
Small catalog (print-on-demand, < 100 products) — search `PreviewData.products()` in memory. No DB full-text search needed.
|
|
|
|
Product maps have: `.name`, `.category`, `.description`, `.slug`, `.price`, `.image_url`, `.image_id`
|
|
|
|
## Changes
|
|
|
|
### 1. CartHook — add search assigns + event handler
|
|
**File:** `lib/simpleshop_theme_web/cart_hook.ex`
|
|
|
|
- Init assigns in `on_mount`: `search_results: []`, `search_query: ""`
|
|
- Handle `"search"` event (from `phx-keyup`):
|
|
- Empty/blank query → assign `search_results: []`, `search_query: ""`
|
|
- Non-empty → filter `PreviewData.products()` by name/category/description (case-insensitive substring match), take 6, assign results
|
|
- Handle `"close_search"` event → clear query + results + hide modal via JS
|
|
|
|
### 2. shop_layout + search_modal — add search attrs and UI
|
|
**File:** `lib/simpleshop_theme_web/components/shop_components/layout.ex`
|
|
|
|
**shop_layout:**
|
|
- Add optional attrs: `search_results` (default `[]`), `search_query` (default `""`)
|
|
- Pass them to `<.search_modal>`
|
|
|
|
**search_modal:**
|
|
- Add `search_results` (list, default `[]`) and `search_query` (string, default `""`) attrs
|
|
- Add `name="query"`, `phx-keyup="search"`, `phx-debounce="200"`, `value={@search_query}` to the input
|
|
- On close button + backdrop click: also push `"close_search"` event
|
|
- Results section below input:
|
|
- Each result: link to `/products/{slug}` with product name, category, formatted price
|
|
- "No results found" when query non-empty but no matches
|
|
- Hint text only shown when no query
|
|
- Click on result: navigate to product, close modal (JS.hide + close_search event)
|
|
|
|
### 3. Page templates — thread search assigns
|
|
**All 8 files in** `lib/simpleshop_theme_web/components/page_templates/`
|
|
|
|
Add two lines to each `<.shop_layout>` call:
|
|
```
|
|
search_results={assigns[:search_results] || []}
|
|
search_query={assigns[:search_query] || ""}
|
|
```
|
|
|
|
Same pattern as `cart_drawer_open` and `cart_status`.
|
|
|
|
## Files to modify
|
|
1. `lib/simpleshop_theme_web/cart_hook.ex`
|
|
2. `lib/simpleshop_theme_web/components/shop_components/layout.ex` (shop_layout + search_modal)
|
|
3. All 8 page templates in `lib/simpleshop_theme_web/components/page_templates/`
|
|
|
|
## Verification
|
|
- Browser: open search modal on multiple pages, type queries, verify results appear and link correctly
|
|
- `mix test` — all existing tests pass
|