diff --git a/client/package.json b/client/package.json index 9f9be47a..463ee731 100644 --- a/client/package.json +++ b/client/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "koji", - "version": "1.3.11", + "version": "1.3.12", "description": "Tool to make RDM routes", "main": "server/dist/index.js", "author": "TurtIeSocks <58572875+TurtIeSocks@users.noreply.github.com>", diff --git a/client/src/pages/map/markers/Polygon.tsx b/client/src/pages/map/markers/Polygon.tsx index 004814df..9ccbb460 100644 --- a/client/src/pages/map/markers/Polygon.tsx +++ b/client/src/pages/map/markers/Polygon.tsx @@ -22,8 +22,6 @@ export function KojiPolygon({ }) { const { setStatic } = useStatic.getState() - const [loadData, setLoadData] = React.useState(false) - const color = getPolygonColor(`${feature.id}`) return ( @@ -32,7 +30,6 @@ export function KojiPolygon({ color={color} eventHandlers={{ click({ latlng }) { - if (!loadData) setLoadData(true) const { lat, lng } = latlng setStatic('clickedLocation', [lng, lat]) }, @@ -145,7 +142,7 @@ export function KojiPolygon({ pane="polygons" > - + ) diff --git a/client/src/pages/map/popups/Polygon.tsx b/client/src/pages/map/popups/Polygon.tsx index c851458a..a82a6f4b 100644 --- a/client/src/pages/map/popups/Polygon.tsx +++ b/client/src/pages/map/popups/Polygon.tsx @@ -10,7 +10,9 @@ import { Select, TextField, Typography, + capitalize, } from '@mui/material' +import RefreshIcon from '@mui/icons-material/Refresh' import useDeepCompareEffect from 'use-deep-compare-effect' import type { MultiPolygon, Polygon } from 'geojson' import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown' @@ -22,6 +24,7 @@ import type { Feature, DbOption, KojiModes, + Category, } from '@assets/types' import { useShapes } from '@hooks/useShapes' import { useStatic } from '@hooks/useStatic' @@ -36,7 +39,6 @@ import { removeThisPolygon, splitMultiPolygons, } from '@services/utils' -import { shallow } from 'zustand/shallow' import { useImportExport } from '@hooks/useImportExport' import { filterPoints, filterPolys } from '@services/geoUtils' import { usePersist } from '@hooks/usePersist' @@ -44,33 +46,79 @@ import { usePersist } from '@hooks/usePersist' const { add, remove, updateProperty } = useShapes.getState().setters const { setRecord } = useDbCache.getState() +const MemoStat = React.memo( + ({ category, id }: { category: Category; id: Feature['id'] }) => { + const [stats, setStats] = React.useState(null) + const [loading, setLoading] = React.useState(false) + const tth = usePersist((s) => s.tth) + const raw = usePersist((s) => s.last_seen) + const feature = useShapes((s) => ({ ...s.Polygon, ...s.MultiPolygon }[id])) + + const getStats = React.useCallback(() => { + setLoading(true) + setStats((prev) => (prev === null ? 0 : null)) + const last_seen = typeof raw === 'string' ? new Date(raw) : raw + fetchWrapper<{ total: number }>(`/internal/data/area_stats/${category}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + area: feature, + last_seen: Math.floor((last_seen?.getTime?.() || 0) / 1000), + tth, + }), + }) + .then((data) => setStats(data?.total ?? 0)) + .finally(() => setLoading(false)) + }, [tth, raw, feature]) + + React.useEffect(() => { + if (stats !== null && !loading) getStats() + }, [tth, raw, feature]) + + return ( + + {capitalize(category)}s: {stats?.toLocaleString() || ''} + + + ) + }, +) + export function PolygonPopup({ feature: refFeature, - loadData, dbRef, }: { feature: Feature - loadData: boolean dbRef: DbOption | null }) { const feature = - useShapes( - (s) => ({ ...s.Polygon, ...s.MultiPolygon }[refFeature.id]), - shallow, - ) || refFeature - const raw = usePersist((s) => s.last_seen) - const tth = usePersist((s) => s.tth) + useShapes((s) => ({ ...s.Polygon, ...s.MultiPolygon }[refFeature.id])) || + refFeature const geofence = useDbCache((s) => s.geofence) - const [active, setActive] = React.useState<{ - spawnpoint: number | null | string - gym: number | null | string - pokestop: number | null | string - }>({ - spawnpoint: null, - gym: null, - pokestop: null, - }) const [name, setName] = React.useState( dbRef?.name || feature.properties?.__name || @@ -103,21 +151,8 @@ export function PolygonPopup({ setDbAnchorEl(null) } - const getState = (category: keyof typeof active) => { - switch (typeof active[category]) { - case 'number': - return active[category]?.toLocaleString() - case 'string': - return active[category] - case 'object': - return - default: - return 'Loading' - } - } - useDeepCompareEffect(() => { - if (feature.geometry.coordinates.length && loadData) { + if (feature.geometry.coordinates.length) { fetchWrapper>('/api/v1/calc/area', { method: 'POST', headers: { @@ -125,33 +160,8 @@ export function PolygonPopup({ }, body: JSON.stringify({ area: feature }), }).then((res) => res && setArea(res.data.area)) - const last_seen = typeof raw === 'string' ? new Date(raw) : raw - - Promise.allSettled( - ['pokestop', 'gym', 'spawnpoint'].map((category) => - fetchWrapper<{ total: number }>( - `/internal/data/area_stats/${category}`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - area: feature, - last_seen: Math.floor((last_seen?.getTime?.() || 0) / 1000), - tth, - }), - }, - ).then((data) => - setActive((prev) => ({ - ...prev, - [category]: data?.total ?? (data || 0), - })), - ), - ), - ) } - }, [feature, loadData, raw, tth]) + }, [feature]) const isKoji = feature.id.toString().endsWith('KOJI') // const isScanner = feature.id.endsWith('SCANNER') @@ -228,13 +238,9 @@ export function PolygonPopup({ - - Pokestops: {getState('pokestop')} - - Gyms: {getState('gym')} - - Spawnpoints: {getState('spawnpoint')} - + + + @@ -470,7 +476,6 @@ export function PolygonPopup({ export const MemoPolyPopup = React.memo( PolygonPopup, (prev, next) => - prev.loadData === next.loadData && prev.feature.geometry.type === next.feature.geometry.type && prev.feature.geometry.coordinates.length === next.feature.geometry.coordinates.length,