diff --git a/docs/superpowers/specs/2026-04-07-mobile-landing-fuelfinder-design.md b/docs/superpowers/specs/2026-04-07-mobile-landing-fuelfinder-design.md new file mode 100644 index 0000000..49ad34d --- /dev/null +++ b/docs/superpowers/specs/2026-04-07-mobile-landing-fuelfinder-design.md @@ -0,0 +1,203 @@ +# FuelFinder Mobile Landing Page — Design Spec + +**Date:** 2026-04-07 +**Scope:** Replace static mobile homepage with a fully functional Livewire-powered landing page, backed by reusable Blade components shared with the desktop search. + +--- + +## Goals + +- Mobile landing page (`/`) becomes the working app — search, recommendation, map, stations list, forecast +- All interactive sections are driven by a single new Livewire component (`FuelFinder`) +- Presentation elements extracted into reusable Blade components consumed by both `FuelFinder` and the existing `StationSearch` +- As lean as possible — no duplicated logic, one station repeater, one map component + +--- + +## Route Change + +```php +// routes/web.php +Route::get('/', FuelFinder::class)->name('home'); +``` + +`/stations` (StationSearch) is kept as-is for now. Migration to shared components happens separately. + +--- + +## Livewire Component: `FuelFinder` + +**File:** `app/Livewire/Public/FuelFinder.php` +**View:** `resources/views/livewire/public/fuel-finder.blade.php` + +### Properties + +| Property | Type | Default | Notes | +|---|---|---|---| +| `$search` | `string` | `''` | Validated: required | +| `$fuelType` | `string` | `'petrol'` | Validated: required | +| `$radius` | `int` | `5` | Validated: 1–20 | +| `$sort` | `string` | `'reliable'` | Validated: in allowed list | +| `$results` | `array` | `[]` | Populated from `/api/stations` | +| `$meta` | `array` | `[]` | Count, lowest/avg price | +| `$prediction` | `?array` | `null` | Populated from `/api/prediction` | +| `$apiError` | `?string` | `null` | Surface API/connection errors | +| `$hasSearched` | `bool` | `false` | Controls section visibility | + +### Methods + +**`findStations()`** +1. Validate all properties +2. Reset results, meta, prediction, apiError, hasSearched +3. Call `GET /api/stations` with postcode, fuel_type, radius (km), sort +4. On success: populate `$results`, `$meta`, set `$hasSearched = true` +5. Call `GET /api/prediction` with `fuel_type` (no lat/lng — national fallback) +6. On success: populate `$prediction` +7. On any failure: set `$apiError` + +**`updatedFuelType()` / `updatedRadius()` / `updatedSort()`** +Re-run `findStations()` if `$hasSearched` is true (live filter refresh). + +--- + +## Blade Components + +All components live under `resources/views/components/fuel/` and are namespaced as `x-fuel.*`. + +### `x-fuel.type-select` +Fuel type ``. Options: 1, 2, 5, 10, 20 miles. +Accepts `wire:model` passthrough. + +### `x-fuel.sort-select` +Sort `