Skip to content

Commit

Permalink
[feat] Map Display in Statistics Dashboard (#86)
Browse files Browse the repository at this point in the history
* feat: added a toggle map button to stats dashboard

* feat: added a simpler map in statics dashboard

* feat: statistics dashboard map showing only filtered incidents now
  • Loading branch information
MysteryCoder456 authored Nov 26, 2024
1 parent ad67b09 commit e92bc4a
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 9 deletions.
94 changes: 94 additions & 0 deletions src/components/StatisticsFilterMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { LatLngBoundsLiteral, LatLngTuple } from 'leaflet'
import { MapContainer, TileLayer, useMap } from 'react-leaflet'
import ZoomControl from '@/components/controls/ZoomControl'
import IncidentLayer from '@/components/layers/IncidentLayer'
import { DB, Incident, MarkerFilters } from '@/types'
import { useLocation } from 'react-router-dom'
import { useEffect } from 'react'
import { INITIAL_BOUNDS, INITIAL_ZOOM } from '@/constants'

interface StatisticsFilterMapProps {
data: DB
incidents: [string, Incident][]
}

function SetInitialBounds() {
const location = useLocation()
const map = useMap()
const coordinates = location.state?.coord
useEffect(() => {
if (coordinates) {
// If coordinates are provided, zoom to that location
const coords: LatLngTuple = [coordinates.lat, coordinates.lng]
map.setView(coords, 15)
} else {
// Otherwise, set to the default
map.setView(INITIAL_BOUNDS, INITIAL_ZOOM)
}
}, [coordinates])
return null
}

export default function StatisticsFilterMap({ data, incidents }: StatisticsFilterMapProps) {
const apiKey = import.meta.env.VITE_STADIA_KEY
const maxBounds: LatLngBoundsLiteral = [
// Southwest coordinate
[-90, -180],
// Northeast coordinate
[90, 180],
]
const filters: MarkerFilters = {
hideCategories: [],
hideTypes: [],
startYear: null,
endYear: null,
hideCountries: [],
hideDepartments: [],
hideMunicipalities: [],
}

// Create a shallow copy of the database and inject filtered incidents into it
const filteredData: DB = { Types: {}, Categories: {}, Incidents: {}, filterBounds: { minYear: 0, maxYear: 0, locations: {} } }
Object.assign(filteredData, data)
filteredData.Incidents = Object.fromEntries(incidents)

// HACK: The height modifier is a little ugly to prevent the map from overflowing the screen at the bottom. Is there a better way to do this?
return (
<div className="relative mt-4 h-[calc(100%-5.5rem)]">
<MapContainer
className="z-0 h-full w-full focus-visible:outline-none"
center={[20, 0]}
zoom={2}
zoomSnap={0.1}
zoomDelta={1}
wheelPxPerZoomLevel={80}
wheelDebounceTime={100}
minZoom={2}
maxZoom={18} // We can adjust this later depending on how detailed the data is.
scrollWheelZoom={true}
zoomControl={false}
maxBounds={maxBounds}
doubleClickZoom={false}
>
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url={`https://tiles.stadiamaps.com/tiles/stamen_terrain/{z}/{x}/{y}{r}.png?api_key=${apiKey}`}
/>
<IncidentLayer
data={filteredData}
selectedIncidentID={null}
setSelectedIncidentID={() => {}}
ref={null}
isAdmin={false}
tmpLocation={null}
setTmpLocation={() => {}}
tmpSelected={false}
filters={filters}
editID={null}
/>
<ZoomControl zoomLevel={2} setFilters={() => {}} />
<SetInitialBounds />
</MapContainer>
</div>
)
}
31 changes: 22 additions & 9 deletions src/pages/StatsDashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// StatsDashboard.tsx
import { DB, Incident } from 'types'
import React, { useMemo, useReducer } from 'react'
import React, { useMemo, useReducer, useState } from 'react'
import IncidentTable from '@/components/IncidentTable'
import StatisticsFilterBar from '@/components/StatisticsFilterBar'
import { calculateBounds } from '@/utils'
import DummyGraph from '@/components/graphs/DummyGraph'
import StatisticsFilterMap from '@/components/StatisticsFilterMap'

export type filterDispatchType = { type: 'ADD_FILTER' | 'REMOVE_FILTER' | 'UPDATE_FILTER'; payload: Partial<filterType> }

Expand Down Expand Up @@ -61,6 +62,7 @@ const filterReducer = (state: filterState, action: filterDispatchType) => {
}

const StatsDashboard: React.FC<StatsDashboardProps> = ({ data }) => {
const [isShowingMap, setIsShowingMap] = useState(false)
const incidents: [string, Incident][] = Object.entries(data.Incidents)
const [filters, dispatchFilters] = useReducer(filterReducer, { index: 0, filters: [] })
const filteredIncidents = useMemo(() => {
Expand All @@ -69,15 +71,26 @@ const StatsDashboard: React.FC<StatsDashboardProps> = ({ data }) => {
const filteredBounds = calculateBounds(Object.fromEntries(filteredIncidents))

return (
<div className="p-4">
<h1 className="text-2xl font-semibold">Estadísticas</h1>
<StatisticsFilterBar data={data} filters={filters.filters} dispatchFilters={dispatchFilters} />
<div className="my-4 flex flex-row flex-wrap gap-4">
<DummyGraph incidents={filteredIncidents} bounds={filteredBounds} />
<DummyGraph incidents={filteredIncidents} bounds={filteredBounds} />
<DummyGraph incidents={filteredIncidents} bounds={filteredBounds} />
<div className="h-full p-4">
<div className="flow-row flex items-center justify-between">
<h1 className="text-2xl font-semibold">Estadísticas</h1>
<button className="m-1 rounded-md px-2 py-1 hover:bg-black hover:bg-opacity-10" onClick={() => setIsShowingMap(!isShowingMap)}>
{isShowingMap ? 'Ocultar Mapa' : 'Mostrar Mapa'}
</button>
</div>
<IncidentTable data={data} incidents={filteredIncidents} />
<StatisticsFilterBar data={data} filters={filters.filters} dispatchFilters={dispatchFilters} />
{isShowingMap ? (
<StatisticsFilterMap data={data} incidents={filteredIncidents} />
) : (
<>
<div className="my-4 flex flex-row flex-wrap gap-4">
<DummyGraph incidents={filteredIncidents} bounds={filteredBounds} />
<DummyGraph incidents={filteredIncidents} bounds={filteredBounds} />
<DummyGraph incidents={filteredIncidents} bounds={filteredBounds} />
</div>
<IncidentTable data={data} incidents={filteredIncidents} />
</>
)}
</div>
)
}
Expand Down

0 comments on commit e92bc4a

Please sign in to comment.