Add nightly town sync from ArcGIS API with autocomplete
All checks were successful
linter / quality (pull_request) Successful in 1m21s
security / Dependency Audit (pull_request) Successful in 1m25s
security / Static Analysis (pull_request) Successful in 1m49s
tests / ci (8.4) (pull_request) Successful in 1m23s
tests / ci (8.5) (pull_request) Successful in 1m27s

- Add towns table with town_pid, town_name, state, population, town_class, date_retired
- Add AustralianState enum with label and abbreviation helpers
- Add Town model with active() and search() scopes
- Add SyncTowns job that paginates ArcGIS API and upserts all 1977 towns
- Schedule SyncTowns to run nightly at 02:00
- Add /towns/search endpoint returning JSON suggestions filtered by name and state
- Add Alpine-powered autocomplete on origin/destination fields in create form
- Add state filter dropdown in journeys card header to narrow autocomplete results
This commit is contained in:
2026-03-06 04:16:55 +00:00
parent a4a31c97e3
commit a37ada96e2
8 changed files with 328 additions and 7 deletions

View File

@@ -1,5 +1,7 @@
<?php
use App\Models\Town;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
@@ -11,9 +13,34 @@ Route::post('/logout', function () {
Auth::logout();
session()->invalidate();
session()->regenerateToken();
return redirect()->route('login');
})->name('logout')->middleware('auth');
// Town autocomplete search
Route::middleware(['auth'])->get('/towns/search', function (Request $request) {
$query = $request->string('query')->trim();
if ($query->length() < 2) {
return response()->json([]);
}
$towns = Town::active()
->search($query)
->when($request->filled('state'), fn ($q) => $q->where('state', $request->integer('state')))
->orderBy('town_name')
->limit(10)
->get(['town_name', 'state']);
return response()->json(
$towns->map(fn ($town) => [
'name' => $town->town_name,
'state' => $town->state->abbreviation(),
'label' => $town->town_name.', '.$town->state->abbreviation(),
])
);
})->name('towns.search');
// Authenticated
Route::middleware(['auth'])->group(function () {
Route::livewire('/dashboard', 'dashboard')->name('dashboard');