From 2c7c3528e443b1edd4db7d5751928f1ef70feb49 Mon Sep 17 00:00:00 2001 From: Developer Date: Mon, 29 Jun 2026 13:22:45 +0800 Subject: [PATCH] feat: implement interactive Barangay polygon map selector in Service Areas --- .../Api/V1/Auth/LoginController.php | 2 +- .../Controllers/Api/V1/Auth/MeController.php | 2 +- .../Api/V1/Geo/BarangayController.php | 7 + .../Api/V1/Geo/ServiceAreaController.php | 11 +- .../Requests/Geo/UpdateServiceAreaRequest.php | 2 + app/Http/Resources/BarangayResource.php | 12 + app/Http/Resources/UserResource.php | 10 + resources/views/admin/service-areas.blade.php | 270 ++++++++++++++++-- tests/Feature/Api/V1/Geo/ServiceAreaTest.php | 21 ++ 9 files changed, 304 insertions(+), 33 deletions(-) diff --git a/app/Http/Controllers/Api/V1/Auth/LoginController.php b/app/Http/Controllers/Api/V1/Auth/LoginController.php index 652026a..1cbd925 100644 --- a/app/Http/Controllers/Api/V1/Auth/LoginController.php +++ b/app/Http/Controllers/Api/V1/Auth/LoginController.php @@ -59,7 +59,7 @@ class LoginController extends ApiController $token = $user->createToken($deviceName); return $this->ok([ - 'user' => new UserResource($user), + 'user' => new UserResource($user->load(['tenant'])), 'token' => $token->plainTextToken, 'token_type' => 'Bearer', ], 'Login successful'); diff --git a/app/Http/Controllers/Api/V1/Auth/MeController.php b/app/Http/Controllers/Api/V1/Auth/MeController.php index bbb05dc..c44238f 100644 --- a/app/Http/Controllers/Api/V1/Auth/MeController.php +++ b/app/Http/Controllers/Api/V1/Auth/MeController.php @@ -12,7 +12,7 @@ class MeController extends ApiController public function __invoke(Request $request): JsonResponse { return $this->ok([ - 'user' => new UserResource($request->user()), + 'user' => new UserResource($request->user()->load(['tenant'])), ]); } } diff --git a/app/Http/Controllers/Api/V1/Geo/BarangayController.php b/app/Http/Controllers/Api/V1/Geo/BarangayController.php index 1394182..abf6a6c 100644 --- a/app/Http/Controllers/Api/V1/Geo/BarangayController.php +++ b/app/Http/Controllers/Api/V1/Geo/BarangayController.php @@ -18,7 +18,14 @@ class BarangayController extends ApiController 'q' => ['nullable', 'string', 'max:100'], ]); + $user = $request->user(); $barangays = Barangay::query() + ->when($user && $user->tenant_id, function ($q) use ($user) { + $tenant = $user->tenant ?: \App\Models\Tenant::find($user->tenant_id); + if ($tenant) { + $q->where('city_municipality_id', $tenant->city_municipality_id); + } + }) ->when($request->filled('city'), function ($q) use ($request) { $q->whereHas('cityMunicipality', fn ($c) => $c->where('psgc_code', $request->string('city')) ->orWhere('code', $request->string('city'))); diff --git a/app/Http/Controllers/Api/V1/Geo/ServiceAreaController.php b/app/Http/Controllers/Api/V1/Geo/ServiceAreaController.php index 1f42a01..177d191 100644 --- a/app/Http/Controllers/Api/V1/Geo/ServiceAreaController.php +++ b/app/Http/Controllers/Api/V1/Geo/ServiceAreaController.php @@ -63,7 +63,16 @@ class ServiceAreaController extends ApiController public function update(UpdateServiceAreaRequest $request, ServiceArea $serviceArea): JsonResponse { - $serviceArea->update($request->validated()); + $data = $request->validated(); + $barangayIds = $data['barangay_ids'] ?? null; + unset($data['barangay_ids']); + + DB::transaction(function () use ($serviceArea, $data, $barangayIds) { + $serviceArea->update($data); + if ($barangayIds !== null) { + $serviceArea->barangays()->sync($barangayIds); + } + }); return $this->ok( new ServiceAreaResource($serviceArea->fresh()->loadCount('barangays')), diff --git a/app/Http/Requests/Geo/UpdateServiceAreaRequest.php b/app/Http/Requests/Geo/UpdateServiceAreaRequest.php index d1fbc3f..2993b0a 100644 --- a/app/Http/Requests/Geo/UpdateServiceAreaRequest.php +++ b/app/Http/Requests/Geo/UpdateServiceAreaRequest.php @@ -28,6 +28,8 @@ class UpdateServiceAreaRequest extends FormRequest ], 'status' => ['sometimes', Rule::in([ServiceArea::STATUS_ACTIVE, ServiceArea::STATUS_INACTIVE])], 'description' => ['sometimes', 'nullable', 'string', 'max:1000'], + 'barangay_ids' => ['nullable', 'array'], + 'barangay_ids.*' => ['integer', 'exists:barangays,id'], ]; } } diff --git a/app/Http/Resources/BarangayResource.php b/app/Http/Resources/BarangayResource.php index 2771e99..3cafcb6 100644 --- a/app/Http/Resources/BarangayResource.php +++ b/app/Http/Resources/BarangayResource.php @@ -9,6 +9,17 @@ class BarangayResource extends JsonResource { public function toArray(Request $request): array { + $boundaryPoints = null; + if ($this->boundary) { + $rings = $this->boundary->getGeometries(); + $ring = $rings->first(); + if ($ring) { + $boundaryPoints = $ring->getGeometries() + ->map(fn ($p) => ['lat' => $p->latitude, 'lng' => $p->longitude]) + ->all(); + } + } + return [ 'id' => $this->id, 'psgc_code' => $this->psgc_code, @@ -20,6 +31,7 @@ class BarangayResource extends JsonResource 'lat' => $this->centroid->latitude, 'lng' => $this->centroid->longitude, ] : null, + 'boundary' => $boundaryPoints, 'city_municipality' => CityMunicipalityResource::make($this->whenLoaded('cityMunicipality')), ]; } diff --git a/app/Http/Resources/UserResource.php b/app/Http/Resources/UserResource.php index e00a2a5..28d6dd9 100644 --- a/app/Http/Resources/UserResource.php +++ b/app/Http/Resources/UserResource.php @@ -22,6 +22,16 @@ class UserResource extends JsonResource 'email_verified_at' => $this->email_verified_at?->toIso8601String(), 'phone_verified_at' => $this->phone_verified_at?->toIso8601String(), 'last_login_at' => $this->last_login_at?->toIso8601String(), + 'tenant' => $this->relationLoaded('tenant') && $this->tenant ? [ + 'id' => $this->tenant->uuid, + 'name' => $this->tenant->name, + 'code' => $this->tenant->code, + 'boundary_polygon' => $this->tenant->boundary_polygon ? (function ($poly) { + $rings = $poly->getGeometries(); + $ring = $rings->first(); + return $ring ? $ring->getGeometries()->map(fn ($p) => ['lat' => $p->latitude, 'lng' => $p->longitude])->all() : null; + })($this->tenant->boundary_polygon) : null, + ] : null, ]; } } diff --git a/resources/views/admin/service-areas.blade.php b/resources/views/admin/service-areas.blade.php index fbe0ab4..daf3516 100644 --- a/resources/views/admin/service-areas.blade.php +++ b/resources/views/admin/service-areas.blade.php @@ -1,6 +1,14 @@ @extends('admin.layouts.app', ['pageTitle' => 'Service Areas']) @section('page') + + +
@@ -28,48 +36,180 @@
-{{-- Slide-over create form --}} +{{-- Slide-over create/edit form --}}