feat: update barangay management and dashboard roles
- Created dashboard-router to separate LGU and Super Admin landing pages - Added Barangays and LGUs statistical cards to Super Admin dashboard - Moved LGU Management to Areas group in sidebar and added API Docs link - Removed geofence spatial validation (ST_Contains) for Barangay creation in both LGU and Super Admin controllers to allow flexible boundaries
This commit is contained in:
@@ -55,20 +55,7 @@ class AdminBarangayController extends ApiController
|
||||
$boundary = $this->buildPolygon($data['boundary']);
|
||||
$centroid = $this->calculateCentroid($boundary);
|
||||
|
||||
if ($tenant->boundary_polygon) {
|
||||
$isContained = DB::selectOne(
|
||||
'SELECT ST_Contains(boundary_polygon, ST_GeomFromText(?, 4326, \'axis-order=long-lat\')) as contained FROM tenants WHERE id = ?',
|
||||
[$boundary->toWkt(), $tenant->id]
|
||||
);
|
||||
|
||||
if (! $isContained || ! $isContained->contained) {
|
||||
return $this->fail(
|
||||
'The drawn Barangay boundary must lie completely within your LGU boundary.',
|
||||
['boundary' => ['The Barangay boundary is outside your LGU border.']],
|
||||
422
|
||||
);
|
||||
}
|
||||
}
|
||||
// Spatial validation check removed as per user request
|
||||
|
||||
// Code auto-generation if empty
|
||||
$city = CityMunicipality::findOrFail($cityId);
|
||||
@@ -130,20 +117,7 @@ class AdminBarangayController extends ApiController
|
||||
$boundary = $this->buildPolygon($data['boundary']);
|
||||
$centroid = $this->calculateCentroid($boundary);
|
||||
|
||||
if ($tenant->boundary_polygon) {
|
||||
$isContained = DB::selectOne(
|
||||
'SELECT ST_Contains(boundary_polygon, ST_GeomFromText(?, 4326, \'axis-order=long-lat\')) as contained FROM tenants WHERE id = ?',
|
||||
[$boundary->toWkt(), $tenant->id]
|
||||
);
|
||||
|
||||
if (! $isContained || ! $isContained->contained) {
|
||||
return $this->fail(
|
||||
'The drawn Barangay boundary must lie completely within your LGU boundary.',
|
||||
['boundary' => ['The Barangay boundary is outside your LGU border.']],
|
||||
422
|
||||
);
|
||||
}
|
||||
}
|
||||
// Spatial validation check removed as per user request
|
||||
|
||||
// Code auto-generation if empty
|
||||
$city = CityMunicipality::findOrFail($cityId);
|
||||
|
||||
@@ -52,24 +52,7 @@ class SuperAdminBarangayController extends ApiController
|
||||
$boundary = $this->buildPolygon($data['boundary']);
|
||||
$centroid = $this->calculateCentroid($boundary);
|
||||
|
||||
// Spatial validation check
|
||||
$cityId = $data['city_municipality_id'];
|
||||
$tenant = Tenant::where('city_municipality_id', $cityId)->first();
|
||||
|
||||
if ($tenant && $tenant->boundary_polygon) {
|
||||
$isContained = DB::selectOne(
|
||||
'SELECT ST_Contains(boundary_polygon, ST_GeomFromText(?, 4326, \'axis-order=long-lat\')) as contained FROM tenants WHERE id = ?',
|
||||
[$boundary->toWkt(), $tenant->id]
|
||||
);
|
||||
|
||||
if (! $isContained || ! $isContained->contained) {
|
||||
return $this->fail(
|
||||
'The drawn Barangay boundary must lie completely within the LGU/Municipality boundary.',
|
||||
['boundary' => ['The Barangay boundary is outside the LGU border.']],
|
||||
422
|
||||
);
|
||||
}
|
||||
}
|
||||
// Spatial validation check removed as per user request
|
||||
|
||||
// Code auto-generation if empty
|
||||
$city = CityMunicipality::findOrFail($cityId);
|
||||
@@ -120,24 +103,7 @@ class SuperAdminBarangayController extends ApiController
|
||||
$boundary = $this->buildPolygon($data['boundary']);
|
||||
$centroid = $this->calculateCentroid($boundary);
|
||||
|
||||
// Spatial validation check
|
||||
$cityId = $data['city_municipality_id'];
|
||||
$tenant = Tenant::where('city_municipality_id', $cityId)->first();
|
||||
|
||||
if ($tenant && $tenant->boundary_polygon) {
|
||||
$isContained = DB::selectOne(
|
||||
'SELECT ST_Contains(boundary_polygon, ST_GeomFromText(?, 4326, \'axis-order=long-lat\')) as contained FROM tenants WHERE id = ?',
|
||||
[$boundary->toWkt(), $tenant->id]
|
||||
);
|
||||
|
||||
if (! $isContained || ! $isContained->contained) {
|
||||
return $this->fail(
|
||||
'The drawn Barangay boundary must lie completely within the LGU/Municipality boundary.',
|
||||
['boundary' => ['The Barangay boundary is outside the LGU border.']],
|
||||
422
|
||||
);
|
||||
}
|
||||
}
|
||||
// Spatial validation check removed as per user request
|
||||
|
||||
// Code auto-generation if empty
|
||||
$city = CityMunicipality::findOrFail($cityId);
|
||||
|
||||
Binary file not shown.
19
resources/views/admin/dashboard-router.blade.php
Normal file
19
resources/views/admin/dashboard-router.blade.php
Normal file
@@ -0,0 +1,19 @@
|
||||
@extends('admin.layouts.app', ['pageTitle' => 'Loading Dashboard...'])
|
||||
|
||||
@section('page')
|
||||
<div class="flex flex-col items-center justify-center h-64 space-y-4">
|
||||
<svg class="h-8 w-8 animate-spin text-verde-600" viewBox="0 0 24 24" fill="none">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 0 1 8-8v4a4 4 0 0 0-4 4H4z"/>
|
||||
</svg>
|
||||
<div class="text-sm text-neutral-500 font-medium tracking-tight">Routing to your dashboard...</div>
|
||||
</div>
|
||||
<script type="module">
|
||||
const user = window.Verde?.getUser();
|
||||
if (user?.role === 'super_admin') {
|
||||
window.location.replace('/admin/superadmin-dashboard');
|
||||
} else {
|
||||
window.location.replace('/admin/lgu-dashboard');
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
@@ -15,6 +15,8 @@
|
||||
['key' => 'pending_households', 'label' => 'Pending households', 'href' => '/admin/households'],
|
||||
['key' => 'verified_households', 'label' => 'Verified households', 'href' => '/admin/households'],
|
||||
['key' => 'service_areas', 'label' => 'Service areas', 'href' => '/admin/service-areas'],
|
||||
['key' => 'barangays', 'label' => 'Barangays', 'href' => '/admin/barangays'],
|
||||
['key' => 'lgus', 'label' => 'LGUs', 'href' => '/admin/lgus'],
|
||||
['key' => 'drop_off_points', 'label' => 'Drop-off points', 'href' => '/admin/drop-off-points'],
|
||||
['key' => 'dumpsites', 'label' => 'Dumpsites', 'href' => '/admin/dumpsites'],
|
||||
['key' => 'qr_batches', 'label' => 'QR batches', 'href' => '/admin/qr-batches'],
|
||||
@@ -81,6 +83,12 @@
|
||||
const sa = await window.Verde.apiFetch('/api/v1/service-areas');
|
||||
if (sa.ok) setStat('service_areas', (sa.body.data ?? []).length);
|
||||
|
||||
const ba = await window.Verde.apiFetch('/api/v1/super-admin/barangays?per_page=1');
|
||||
if (ba.ok) setStat('barangays', ba.body.meta?.total ?? 0);
|
||||
|
||||
const lgus = await window.Verde.apiFetch('/api/v1/super-admin/tenants?per_page=1');
|
||||
if (lgus.ok) setStat('lgus', lgus.body.meta?.total ?? 0);
|
||||
|
||||
const dop = await window.Verde.apiFetch('/api/v1/admin/drop-off-points?per_page=1');
|
||||
if (dop.ok) setStat('drop_off_points', dop.body.meta?.total ?? 0);
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
'Areas' => [
|
||||
['href' => '/admin/service-areas', 'label' => 'Service Areas', 'icon' => 'globe'],
|
||||
['href' => '/admin/barangays', 'label' => 'Barangays', 'icon' => 'pin'],
|
||||
['href' => '/admin/lgus', 'label' => 'LGU Management', 'icon' => 'globe', 'super_admin_only' => true],
|
||||
],
|
||||
'Finance' => [
|
||||
['href' => '/admin/finance', 'label' => 'Payments', 'icon' => 'cash'],
|
||||
@@ -38,8 +39,8 @@
|
||||
['href' => '/admin/settings', 'label' => 'System Config', 'icon' => 'cog'],
|
||||
],
|
||||
'System Admin' => [
|
||||
['href' => '/admin/lgus', 'label' => 'LGU Management', 'icon' => 'globe'],
|
||||
['href' => '/admin/system-users', 'label' => 'User Accounts', 'icon' => 'users'],
|
||||
['href' => '/docs/api', 'label' => 'API Docs', 'icon' => 'route', 'external' => true],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -89,11 +90,16 @@
|
||||
$disabled = ! empty($item['disabled']);
|
||||
$href = $disabled ? '#' : $item['href'];
|
||||
$active = ! $disabled && $isActive(ltrim($item['href'], '/'));
|
||||
$superAdminOnly = ! empty($item['super_admin_only']);
|
||||
$classes = 'nav-link ' . ($active ? 'is-active ' : '') . ($disabled ? 'is-disabled ' : '');
|
||||
if ($superAdminOnly) {
|
||||
$classes .= ' hidden super-admin-item';
|
||||
}
|
||||
@endphp
|
||||
<a href="{{ $href }}"
|
||||
@if($disabled) onclick="event.preventDefault(); window.Verde?.toast('{{ $item['label'] }} ships in a later module.', 'info');" @endif
|
||||
@if(! empty($item['external'])) target="_blank" rel="noopener" @endif
|
||||
class="nav-link {{ $active ? 'is-active' : '' }} {{ $disabled ? 'is-disabled' : '' }}">
|
||||
class="{{ trim($classes) }}">
|
||||
{!! $renderIcon($item['icon']) !!}
|
||||
<span class="flex-1">{{ $item['label'] }}</span>
|
||||
@if ($disabled)
|
||||
@@ -111,6 +117,7 @@
|
||||
// Show System Admin group only for super_admin
|
||||
if (user.role === 'super_admin') {
|
||||
document.getElementById('nav-group-superadmin')?.classList.remove('hidden');
|
||||
document.querySelectorAll('.super-admin-item').forEach(el => el.classList.remove('hidden'));
|
||||
}
|
||||
|
||||
// Update role badge
|
||||
|
||||
@@ -14,7 +14,9 @@ Route::get('/qr/{serial}', function ($serial) {
|
||||
})->name('qr.verify');
|
||||
|
||||
Route::prefix('admin')->group(function () {
|
||||
Route::view('/dashboard', 'admin.lgu-dashboard')->name('admin.dashboard');
|
||||
Route::view('/dashboard', 'admin.dashboard-router')->name('admin.dashboard');
|
||||
Route::view('/lgu-dashboard', 'admin.lgu-dashboard')->name('admin.lgu-dashboard');
|
||||
Route::view('/superadmin-dashboard', 'admin.dashboard')->name('admin.superadmin-dashboard');
|
||||
Route::view('/households', 'admin.households')->name('admin.households');
|
||||
Route::view('/service-areas', 'admin.service-areas')->name('admin.service-areas');
|
||||
Route::view('/qr-batches', 'admin.qr-batches')->name('admin.qr-batches');
|
||||
|
||||
Reference in New Issue
Block a user