feat: update admin panel labels and adjust API endpoints for areas
This commit is contained in:
@@ -18,7 +18,7 @@ const navLinks = [
|
||||
]
|
||||
|
||||
const { isAuthenticated, user, logout } = useAuth()
|
||||
const panelLabel = computed(() => user.value?.role?.toUpperCase() === 'ADMIN' ? 'Pannello admin' : 'Dashboard')
|
||||
const panelLabel = computed(() => user.value?.role?.toUpperCase() === 'ADMIN' ? 'Pannello' : 'Dashboard')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -21,7 +21,7 @@ export const useAdmin = () => {
|
||||
useApiFetch<OkResponse>(`/api/v1/admin/users/${id}/roles`, { method: 'PATCH', body })
|
||||
|
||||
const getAreas = () =>
|
||||
useApiFetch<AreaListResponse>('/api/v1/admin/areas', { method: 'GET' })
|
||||
useApiFetch<AreaListResponse>('/api/v1/areas', { method: 'GET' })
|
||||
|
||||
const createArea = (body: CreateAreaRequest) =>
|
||||
useApiFetch<OkResponse>('/api/v1/admin/areas', { method: 'POST', body })
|
||||
@@ -58,4 +58,4 @@ export const useAdmin = () => {
|
||||
getModerationFlags,
|
||||
updateModerationFlag,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+121
-12
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { isWithinBariBounds } from '~/utils/bari'
|
||||
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import type { Map as LeafletMap, CircleMarker, LatLngBoundsExpression } from 'leaflet'
|
||||
import { BARI_BOUNDS, BARI_CENTER, isWithinBariBounds } from '~/utils/bari'
|
||||
|
||||
// 1. API Fetching Logic
|
||||
const { getOpenDataReports } = usePublic()
|
||||
@@ -35,6 +36,10 @@ const prevPage = () => {
|
||||
|
||||
// 2. View Toggle (Grid vs Map)
|
||||
const currentView = ref<'grid' | 'map'>('grid')
|
||||
const mapContainer = ref<HTMLElement | null>(null)
|
||||
let leaflet: typeof import('leaflet') | null = null
|
||||
let map: LeafletMap | null = null
|
||||
let markers: CircleMarker[] = []
|
||||
|
||||
// 3. Helper to style status badges
|
||||
const getStatusBadge = (status: string) => {
|
||||
@@ -44,6 +49,99 @@ const getStatusBadge = (status: string) => {
|
||||
default: return { class: 'bg-info', text: status, icon: 'it-info-circle' }
|
||||
}
|
||||
}
|
||||
|
||||
const loadLeaflet = async () => {
|
||||
if (leaflet) return leaflet
|
||||
leaflet = await import('leaflet')
|
||||
return leaflet
|
||||
}
|
||||
|
||||
const clearMarkers = () => {
|
||||
if (!map) return
|
||||
markers.forEach((marker) => marker.removeFrom(map!))
|
||||
markers = []
|
||||
}
|
||||
|
||||
const renderMapMarkers = async () => {
|
||||
if (!import.meta.client || !mapContainer.value) return
|
||||
|
||||
const L = await loadLeaflet()
|
||||
if (!map) return
|
||||
|
||||
clearMarkers()
|
||||
|
||||
if (visibleReports.value.length === 0) {
|
||||
map.setView(BARI_CENTER, 12)
|
||||
return
|
||||
}
|
||||
|
||||
visibleReports.value.forEach((report) => {
|
||||
const marker = L.circleMarker([report.latitude, report.longitude], {
|
||||
radius: 8,
|
||||
weight: 2,
|
||||
color: '#ffffff',
|
||||
fillColor: getStatusBadge(report.status).class === 'bg-success' ? '#008758' : getStatusBadge(report.status).class === 'bg-secondary' ? '#5c6f82' : '#2f80ed',
|
||||
fillOpacity: 0.95,
|
||||
})
|
||||
|
||||
marker.bindPopup(`
|
||||
<div class="open-data-popup">
|
||||
<strong>${report.category_name}</strong><br/>
|
||||
<span>ID #${report.id}</span><br/>
|
||||
<span>${report.area_name || 'Area comunale non specificata'}</span><br/>
|
||||
<span>Segnalato ${new Date(report.created_at).toLocaleDateString('it-IT')}</span>
|
||||
</div>
|
||||
`)
|
||||
|
||||
marker.addTo(map!)
|
||||
markers.push(marker)
|
||||
})
|
||||
|
||||
const fitBounds: LatLngBoundsExpression = visibleReports.value.map((report) => [report.latitude, report.longitude])
|
||||
map.fitBounds(fitBounds, { padding: [32, 32], maxZoom: 15 })
|
||||
}
|
||||
|
||||
const initMap = async () => {
|
||||
if (!import.meta.client || !mapContainer.value || map) return
|
||||
|
||||
const L = await loadLeaflet()
|
||||
const bariBounds = L.latLngBounds(
|
||||
[BARI_BOUNDS.south, BARI_BOUNDS.west],
|
||||
[BARI_BOUNDS.north, BARI_BOUNDS.east]
|
||||
)
|
||||
|
||||
map = L.map(mapContainer.value, {
|
||||
maxBounds: bariBounds,
|
||||
maxBoundsViscosity: 1,
|
||||
minZoom: 11,
|
||||
}).setView(BARI_CENTER, 12)
|
||||
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© OpenStreetMap contributors'
|
||||
}).addTo(map)
|
||||
|
||||
await renderMapMarkers()
|
||||
}
|
||||
|
||||
watch(currentView, async (view) => {
|
||||
if (view !== 'map') return
|
||||
await nextTick()
|
||||
await initMap()
|
||||
map?.invalidateSize()
|
||||
await renderMapMarkers()
|
||||
})
|
||||
|
||||
watch(visibleReports, async () => {
|
||||
if (currentView.value === 'map' && map) {
|
||||
await renderMapMarkers()
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearMarkers()
|
||||
map?.remove()
|
||||
map = null
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -175,18 +273,15 @@ const getStatusBadge = (status: string) => {
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- MAP VIEW (Placeholder for Leaflet/Mapbox) -->
|
||||
<!-- MAP VIEW -->
|
||||
<div v-else-if="currentView === 'map'" class="map-view-wrapper">
|
||||
<div class="alert alert-info d-flex align-items-center" role="alert">
|
||||
<span>La visualizzazione mappa è un modulo interattivo (ad es. Leaflet o Mapbox) che utilizzerà le coordinate <strong>latitudine</strong> e <strong>longitudine</strong> fornite dalle API.</span>
|
||||
</div>
|
||||
<div class="bg-light border rounded d-flex align-items-center justify-content-center" style="height: 500px;">
|
||||
<div class="text-center text-muted">
|
||||
<BIIcon name="it-map" size="xl" class="mb-3 opacity-50" />
|
||||
<h4 class="h5">Mappa Interattiva</h4>
|
||||
<p>Caricamento dei {{ visibleReports.length || 0 }} punti geografici in corso...</p>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
|
||||
<p class="text-muted mb-0">Mappa pubblica delle segnalazioni nell'area di Bari.</p>
|
||||
<span class="badge bg-light text-dark border">{{ visibleReports.length }} punti</span>
|
||||
</div>
|
||||
<ClientOnly>
|
||||
<div ref="mapContainer" class="open-data-map rounded border"></div>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -206,4 +301,18 @@ const getStatusBadge = (status: string) => {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.1) !important;
|
||||
}
|
||||
|
||||
.open-data-map {
|
||||
height: 520px;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
:global(.open-data-popup) {
|
||||
color: #17324d;
|
||||
font-family: "Titillium Web", Arial, sans-serif;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.4;
|
||||
min-width: 12rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user