From b437b87fc9c4ed97aa094d551e69bde5caf19f20 Mon Sep 17 00:00:00 2001 From: TurtIeSocks <58572875+TurtIeSocks@users.noreply.github.com> Date: Mon, 20 Jun 2022 01:19:15 -0400 Subject: [PATCH 1/8] Expand Scan Areas List - Normalize manual areas - Add parents property support - Fix instanceof error --- server/src/routes/rootRouter.js | 13 +-- server/src/services/api/fetchJson.js | 5 +- server/src/services/config.js | 50 +++++++++--- src/components/QueryData.jsx | 6 +- src/components/layout/drawer/Areas.jsx | 102 ++++++++++++++++-------- src/components/layout/drawer/Drawer.jsx | 3 +- 6 files changed, 114 insertions(+), 65 deletions(-) diff --git a/server/src/routes/rootRouter.js b/server/src/routes/rootRouter.js index 4a198dec3..dd61cf1d3 100644 --- a/server/src/routes/rootRouter.js +++ b/server/src/routes/rootRouter.js @@ -1,6 +1,5 @@ /* eslint-disable no-console */ const express = require('express') -const { default: center } = require('@turf/center') const authRouter = require('./authRouter') const clientRouter = require('./clientRouter') @@ -46,7 +45,7 @@ rootRouter.post('/clientError', (req) => { rootRouter.get('/area/:area/:zoom?', (req, res) => { const { area, zoom } = req.params try { - const { scanAreas, manualAreas } = config + const { scanAreas } = config const validScanAreas = scanAreas[req.headers.host] ? scanAreas[req.headers.host] : scanAreas.main @@ -55,13 +54,7 @@ rootRouter.get('/area/:area/:zoom?', (req, res) => { (a) => a.properties.name.toLowerCase() === area.toLowerCase(), ) if (foundArea) { - const [lon, lat] = center(foundArea).geometry.coordinates - return res.redirect(`/@/${lat}/${lon}/${zoom || 18}`) - } - if (manualAreas.length) { - const { lat, lon } = manualAreas.find( - (a) => a.name.toLowerCase() === area.toLowerCase(), - ) + const [lat, lon] = foundArea.properties.center return res.redirect(`/@/${lat}/${lon}/${zoom || 18}`) } return res.redirect('/404') @@ -166,7 +159,6 @@ rootRouter.get('/settings', async (req, res) => { react: {}, leaflet: {}, }, - manualAreas: config.manualAreas || {}, icons: { ...config.icons, styles: Event.uicons }, scanner: { scannerType: config.scanner.backendConfig.platform, @@ -199,7 +191,6 @@ rootRouter.get('/settings', async (req, res) => { // keys that are being sent to the frontend but are not options const ignoreKeys = [ 'map', - 'manualAreas', 'limit', 'icons', 'scanner', diff --git a/server/src/services/api/fetchJson.js b/server/src/services/api/fetchJson.js index 1e9946967..230e275aa 100644 --- a/server/src/services/api/fetchJson.js +++ b/server/src/services/api/fetchJson.js @@ -1,6 +1,5 @@ /* eslint-disable no-console */ const fetch = require('node-fetch') -const { AbortError } = require('node-fetch') module.exports = async function fetchJson( url, @@ -21,9 +20,7 @@ module.exports = async function fetchJson( } return response.json() } catch (e) { - if (e instanceof AbortError) { - console.log('Request to', url, 'timed out and was aborted') - } else if (log) { + if (log) { console.warn(e) } else if (e instanceof Error) { console.warn(e.message, '\n', e.code, `\nUnable to fetch ${url}`) diff --git a/server/src/services/config.js b/server/src/services/config.js index bd88fb8d3..f805ddfee 100644 --- a/server/src/services/config.js +++ b/server/src/services/config.js @@ -4,14 +4,15 @@ process.env.NODE_CONFIG_DIR = `${__dirname}/../configs` const fs = require('fs') -const path = require('path') +const { resolve } = require('path') const dotenv = require('dotenv') +const { default: center } = require('@turf/center') dotenv.config() const config = require('config') -if (!fs.existsSync(path.resolve(`${__dirname}/../configs/local.json`))) { +if (!fs.existsSync(resolve(`${__dirname}/../configs/local.json`))) { // add database env variables from .env or docker-compose const { SCANNER_DB_HOST, @@ -82,7 +83,7 @@ if (!fs.existsSync(path.resolve(`${__dirname}/../configs/local.json`))) { ) } } -if (fs.existsSync(path.resolve(`${__dirname}/../configs/config.json`))) { +if (fs.existsSync(resolve(`${__dirname}/../configs/config.json`))) { console.log( '[CONFIG] Config v1 (config.json) found, it is fine to leave it but make sure you are using and updating local.json instead.', ) @@ -166,14 +167,44 @@ config.authMethods = [ }) // Load each areas.json -const loadScanPolygons = (fileName) => - fs.existsSync(path.resolve(`${__dirname}/../configs/${fileName}`)) - ? require(`../configs/${fileName}`) +const loadScanPolygons = (fileName) => { + const geojson = fs.existsSync(resolve(`${__dirname}/../configs/${fileName}`)) + ? JSON.parse(fs.readFileSync(resolve(__dirname, `../configs/${fileName}`))) : { features: [] } + return { + ...geojson, + features: geojson.features.map((f) => ({ + ...f, + properties: { + ...f.properties, + center: center(f).geometry.coordinates.reverse(), + }, + })), + } +} // Check if an areas.json exists config.scanAreas = { - main: loadScanPolygons(config.map.geoJsonFileName), + main: config.manualAreas.length + ? { + type: 'FeatureCollection', + features: config.manualAreas + .filter((area) => ['lat', 'lon', 'name'].every((k) => k in area)) + .map((area) => ({ + type: 'Feature', + properties: { + name: area.name, + center: [area.lat, area.lon], + zoom: area.zoom, + parent: area.parent, + }, + geometry: { + type: 'Polygon', + coordinates: [[[area.lon, area.lat]]], + }, + })), + } + : loadScanPolygons(config.map.geoJsonFileName), ...Object.fromEntries( config.multiDomains.map((d) => [ d.general?.geoJsonFileName ? d.domain : 'main', @@ -210,9 +241,4 @@ if ( config.authentication.alwaysEnabledPerms = enabled } -// Map manual areas -config.manualAreas = Object.fromEntries( - config.manualAreas.map((area) => [area.name, area]), -) - module.exports = config diff --git a/src/components/QueryData.jsx b/src/components/QueryData.jsx index bd01d5e50..6af23c606 100644 --- a/src/components/QueryData.jsx +++ b/src/components/QueryData.jsx @@ -132,8 +132,8 @@ export default function QueryData({ } } - const renderedData = data || previousData || {} - return renderedData[category] ? ( + const renderedData = data || previousData || { [category]: [] } + return ( <> )} - ) : null + ) } diff --git a/src/components/layout/drawer/Areas.jsx b/src/components/layout/drawer/Areas.jsx index 1c0eee568..b10172647 100644 --- a/src/components/layout/drawer/Areas.jsx +++ b/src/components/layout/drawer/Areas.jsx @@ -1,18 +1,36 @@ import React from 'react' import { useQuery } from '@apollo/client' -import { Paper, MenuItem, MenuList, Typography } from '@material-ui/core' -import center from '@turf/center' +import { Grid, Paper, MenuItem, Typography } from '@material-ui/core' import { useMap } from 'react-leaflet' import Utility from '@services/Utility' import Query from '@services/Query' -export default function AreaDropDown({ scanAreasZoom, manualAreas }) { - const { data } = useQuery(Query.scanAreas(), { +export default function AreaDropDown({ scanAreasZoom }) { + const { data, loading, error } = useQuery(Query.scanAreas(), { variables: { version: inject.VERSION }, }) const map = useMap() + if (loading || error) return null + + const stuff = React.useMemo(() => { + const parents = {} + data.scanAreas[0].features.forEach((feature) => { + if (feature.properties.parent && !parents[feature.properties.parent]) { + parents[feature.properties.parent] = { + details: data.scanAreas[0].features.find( + (area) => area.properties.name === feature.properties.parent, + ), + children: data.scanAreas[0].features.filter( + (area) => area.properties.parent === feature.properties.parent, + ), + } + } + }) + return parents + }, []) + return ( - {Object.keys(manualAreas).length ? ( - - {Object.keys(manualAreas).map((area) => ( - ( + + { + map.flyTo( + details.properties.center, + details.properties.zoom || scanAreasZoom, + ) + } + : undefined + } + > + + + {Utility.getProperName(parent)} + + + + {children.map((feat, i) => ( + { - const { lat, lon, zoom } = manualAreas[area] - map.flyTo([lat, lon], zoom || scanAreasZoom) + map.flyTo( + feat.properties.center, + feat.properties.zoom || scanAreasZoom, + ) }} > - - {area} - - - ))} - - ) : ( - - {data && - data.scanAreas[0].features.map((area) => ( - { - const [lon, lat] = center(area).geometry.coordinates - map.flyTo([lat, lon], scanAreasZoom) - }} - > - - {Utility.getProperName(area.properties.name)} + + + {Utility.getProperName(feat.properties.name)} - ))} - - )} + + ))} + + ))} ) } diff --git a/src/components/layout/drawer/Drawer.jsx b/src/components/layout/drawer/Drawer.jsx index da5ff7985..8ca6426bf 100644 --- a/src/components/layout/drawer/Drawer.jsx +++ b/src/components/layout/drawer/Drawer.jsx @@ -36,7 +36,6 @@ export default function Sidebar({ const ui = useStatic((state) => state.ui) const staticUserSettings = useStatic((state) => state.userSettings) const { - manualAreas, map: { title, scanAreasZoom, noScanAreaOverlay, enableQuestSetSelector }, } = useStatic((state) => state.config) const available = useStatic((s) => s.available) @@ -137,7 +136,7 @@ export default function Sidebar({ )} {category === 'scanAreas' && ( - + )} From 7424eb7e7f59287f6a44094a86a665743b6bb180 Mon Sep 17 00:00:00 2001 From: TurtIeSocks <58572875+TurtIeSocks@users.noreply.github.com> Date: Mon, 20 Jun 2022 01:27:43 -0400 Subject: [PATCH 2/8] Borders & Fix for areas.json --- src/components/layout/drawer/Areas.jsx | 59 ++++++++++++++++---------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/components/layout/drawer/Areas.jsx b/src/components/layout/drawer/Areas.jsx index b10172647..94108f1ce 100644 --- a/src/components/layout/drawer/Areas.jsx +++ b/src/components/layout/drawer/Areas.jsx @@ -14,7 +14,7 @@ export default function AreaDropDown({ scanAreasZoom }) { if (loading || error) return null - const stuff = React.useMemo(() => { + const areas = React.useMemo(() => { const parents = {} data.scanAreas[0].features.forEach((feature) => { if (feature.properties.parent && !parents[feature.properties.parent]) { @@ -28,6 +28,9 @@ export default function AreaDropDown({ scanAreasZoom }) { } } }) + if (!Object.keys(parents).length) { + parents[''] = { children: data.scanAreas[0].features } + } return parents }, []) @@ -41,44 +44,54 @@ export default function AreaDropDown({ scanAreasZoom }) { backgroundColor: '#212121', }} > - {Object.entries(stuff).map(([parent, { details, children }]) => ( + {Object.entries(areas).map(([parent, { details, children }]) => ( - { - map.flyTo( - details.properties.center, - details.properties.zoom || scanAreasZoom, - ) - } - : undefined - } - > - - - {Utility.getProperName(parent)} - - - + {Boolean(parent) && ( + { + map.flyTo( + details.properties.center, + details.properties.zoom || scanAreasZoom, + ) + } + : undefined + } + style={{ border: '1px solid grey' }} + > + + + {Utility.getProperName(parent)} + + + + )} {children.map((feat, i) => ( { map.flyTo( feat.properties.center, feat.properties.zoom || scanAreasZoom, ) }} + style={{ border: '1px solid grey' }} > Date: Mon, 20 Jun 2022 09:22:12 -0400 Subject: [PATCH 3/8] Update Examples --- server/src/configs/areas.example.json | 3 ++- server/src/configs/local.example.json | 14 +++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/server/src/configs/areas.example.json b/server/src/configs/areas.example.json index 7d8b916f9..ff2fa9e31 100644 --- a/server/src/configs/areas.example.json +++ b/server/src/configs/areas.example.json @@ -34,7 +34,8 @@ "stroke": "#352BFF", "stroke-width": 2.0, "fill": "#0651FF", - "hidden": false + "hidden": false, + "parent": "USA" } } ] diff --git a/server/src/configs/local.example.json b/server/src/configs/local.example.json index f7cc0591f..05ba899d1 100644 --- a/server/src/configs/local.example.json +++ b/server/src/configs/local.example.json @@ -302,10 +302,22 @@ "lon": -74.0174788, "zoom": 15 }, + { + "name": "California", + "lat": 37.1931249, + "lon": -123.7961458 + }, { "name": "San Francisco", "lat": 37.79539194255634, - "lon": -122.39333173075096 + "lon": -122.39333173075096, + "parent": "California" + }, + { + "name": "Houston", + "lat": 33.6145517, + "lon": -108.6038347, + "parent": "Texas" } ] } \ No newline at end of file From 047ecf0aaf74f33ffb2760f3a0e52c21a1fa29e4 Mon Sep 17 00:00:00 2001 From: TurtIeSocks <58572875+TurtIeSocks@users.noreply.github.com> Date: Mon, 20 Jun 2022 15:43:27 -0400 Subject: [PATCH 4/8] Better fill/stroke support - Respect geojson fill and stroke colors - Consolidate some of the logic into initial config instead of in resolvers - Change the spacing on WithSubItems for better locale support --- server/src/graphql/resolvers.js | 7 --- server/src/services/config.js | 45 ++++++++++--------- src/components/layout/drawer/Areas.jsx | 14 ++++-- src/components/layout/drawer/WithSubItems.jsx | 4 +- src/components/tiles/ScanArea.jsx | 6 ++- 5 files changed, 42 insertions(+), 34 deletions(-) diff --git a/server/src/graphql/resolvers.js b/server/src/graphql/resolvers.js index d6d90151f..0ad7f4371 100644 --- a/server/src/graphql/resolvers.js +++ b/server/src/graphql/resolvers.js @@ -188,13 +188,6 @@ module.exports = { ? config.scanAreas[req.headers.host] : config.scanAreas.main if (perms?.scanAreas && scanAreas.features.length) { - try { - scanAreas.features = scanAreas.features - .filter((feature) => !feature.properties.hidden) - .sort((a, b) => (a.properties.name > b.properties.name ? 1 : -1)) - } catch (e) { - console.warn('[WARN] Failed to sort scan areas', e.message) - } return [scanAreas] } return [{ features: [] }] diff --git a/server/src/services/config.js b/server/src/services/config.js index f805ddfee..32106e96e 100644 --- a/server/src/services/config.js +++ b/server/src/services/config.js @@ -173,13 +173,16 @@ const loadScanPolygons = (fileName) => { : { features: [] } return { ...geojson, - features: geojson.features.map((f) => ({ - ...f, - properties: { - ...f.properties, - center: center(f).geometry.coordinates.reverse(), - }, - })), + features: geojson.features + .filter((f) => !f.properties.hidden) + .map((f) => ({ + ...f, + properties: { + ...f.properties, + center: center(f).geometry.coordinates.reverse(), + }, + })) + .sort((a, b) => a.properties.name.localeCompare(b.properties.name)), } } @@ -190,19 +193,21 @@ config.scanAreas = { type: 'FeatureCollection', features: config.manualAreas .filter((area) => ['lat', 'lon', 'name'].every((k) => k in area)) - .map((area) => ({ - type: 'Feature', - properties: { - name: area.name, - center: [area.lat, area.lon], - zoom: area.zoom, - parent: area.parent, - }, - geometry: { - type: 'Polygon', - coordinates: [[[area.lon, area.lat]]], - }, - })), + .map((area) => { + const { lat, lon, ...rest } = area + return { + type: 'Feature', + properties: { + center: [lat, lon], + ...rest, + }, + geometry: { + type: 'Polygon', + coordinates: [[[lon, lat]]], + }, + } + }) + .sort((a, b) => a.properties.name.localeCompare(b.properties.name)), } : loadScanPolygons(config.map.geoJsonFileName), ...Object.fromEntries( diff --git a/src/components/layout/drawer/Areas.jsx b/src/components/layout/drawer/Areas.jsx index 94108f1ce..1bd11acb7 100644 --- a/src/components/layout/drawer/Areas.jsx +++ b/src/components/layout/drawer/Areas.jsx @@ -15,7 +15,7 @@ export default function AreaDropDown({ scanAreasZoom }) { if (loading || error) return null const areas = React.useMemo(() => { - const parents = {} + const parents = { '': { children: [] } } data.scanAreas[0].features.forEach((feature) => { if (feature.properties.parent && !parents[feature.properties.parent]) { parents[feature.properties.parent] = { @@ -26,6 +26,8 @@ export default function AreaDropDown({ scanAreasZoom }) { (area) => area.properties.parent === feature.properties.parent, ), } + } else { + parents[''].children.push(feature) } }) if (!Object.keys(parents).length) { @@ -65,7 +67,10 @@ export default function AreaDropDown({ scanAreasZoom }) { } : undefined } - style={{ border: '1px solid grey' }} + style={{ + border: `1px solid ${details.properties.color || 'grey'}`, + backgroundColor: details.properties.fillColor || 'none', + }} > - + {category === 'scanAreas' ? t('show_polygons') : t(Utility.camelToSnake(subItem))} - + {filterCategory} {enableQuestSetSelector === true && diff --git a/src/components/tiles/ScanArea.jsx b/src/components/tiles/ScanArea.jsx index 721974595..0186ad0dc 100644 --- a/src/components/tiles/ScanArea.jsx +++ b/src/components/tiles/ScanArea.jsx @@ -20,10 +20,12 @@ export default function ScanAreaTile({ const name = feature.properties.name.toLowerCase() const popupContent = Utility.getProperName(name) layer.setStyle({ - color: feature.properties.stroke || '#3388ff', + color: + feature.properties.color || feature.properties.stroke || '#3388ff', weight: feature.properties['stroke-width'] || 3, opacity: feature.properties['stroke-opacity'] || 1, - fillColor: feature.properties.fill || '#3388ff', + fillColor: + feature.properties.fillColor || feature.properties.fill || '#3388ff', fillOpacity: selectedAreas && selectedAreas.includes(name) && From 6b6a9d1c88dd3e28ff95faa1d90ecc6be9d13e18 Mon Sep 17 00:00:00 2001 From: TurtIeSocks <58572875+TurtIeSocks@users.noreply.github.com> Date: Mon, 20 Jun 2022 16:13:19 -0400 Subject: [PATCH 5/8] Fallback catches --- src/components/layout/drawer/Areas.jsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/layout/drawer/Areas.jsx b/src/components/layout/drawer/Areas.jsx index 1bd11acb7..d02f95e02 100644 --- a/src/components/layout/drawer/Areas.jsx +++ b/src/components/layout/drawer/Areas.jsx @@ -60,16 +60,18 @@ export default function AreaDropDown({ scanAreasZoom }) { onClick={ details ? () => { - map.flyTo( - details.properties.center, - details.properties.zoom || scanAreasZoom, - ) + if (details?.properties) { + map.flyTo( + details.properties.center, + details.properties.zoom || scanAreasZoom, + ) + } } : undefined } style={{ - border: `1px solid ${details.properties.color || 'grey'}`, - backgroundColor: details.properties.fillColor || 'none', + border: `1px solid ${details?.properties?.color || 'grey'}`, + backgroundColor: details?.properties?.fillColor || 'none', }} > From 304273578396e782f0fd181aa0c0ae8bcdca8b64 Mon Sep 17 00:00:00 2001 From: TurtIeSocks <58572875+TurtIeSocks@users.noreply.github.com> Date: Mon, 20 Jun 2022 16:34:13 -0400 Subject: [PATCH 6/8] Better odd count handling --- src/components/layout/drawer/Areas.jsx | 27 ++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/components/layout/drawer/Areas.jsx b/src/components/layout/drawer/Areas.jsx index d02f95e02..e3f2b12c6 100644 --- a/src/components/layout/drawer/Areas.jsx +++ b/src/components/layout/drawer/Areas.jsx @@ -33,6 +33,11 @@ export default function AreaDropDown({ scanAreasZoom }) { if (!Object.keys(parents).length) { parents[''] = { children: data.scanAreas[0].features } } + Object.values(parents).forEach(({ children }) => { + if (children.length % 2 === 1) { + children.push({ type: 'Feature', properties: { name: '' } }) + } + }) return parents }, []) @@ -40,7 +45,7 @@ export default function AreaDropDown({ scanAreasZoom }) { - + { - map.flyTo( - feat.properties.center, - feat.properties.zoom || scanAreasZoom, - ) + if (feat.properties?.center) { + map.flyTo( + feat.properties.center, + feat.properties.zoom || scanAreasZoom, + ) + } }} style={{ border: `1px solid ${feat.properties.color || 'grey'}`, backgroundColor: feat.properties.fillColor || 'none', }} > - + - {Utility.getProperName(feat.properties.name)} + {feat.properties.name ? ( + Utility.getProperName(feat.properties.name) + ) : ( + <>  + )} From f6e8c6a827e5d0553458be4a40fed56948727d43 Mon Sep 17 00:00:00 2001 From: TurtIeSocks <58572875+TurtIeSocks@users.noreply.github.com> Date: Mon, 20 Jun 2022 22:41:42 -0400 Subject: [PATCH 7/8] Move logic to the server - Move parent finding logic to the server for simplicity - Add a GQL endpoint and all other relevant code needed for that - Add a configurable height value for the menu --- .../configs/custom-environment-variables.json | 4 ++ server/src/configs/default.json | 1 + server/src/graphql/mapTypes.js | 6 +++ server/src/graphql/resolvers.js | 13 ++++++ server/src/graphql/typeDefs.js | 1 + server/src/services/config.js | 30 ++++++++++++++ src/components/layout/drawer/Areas.jsx | 41 ++++--------------- src/components/layout/drawer/Drawer.jsx | 13 +++++- src/services/Query.js | 6 ++- src/services/queries/scanAreas.js | 16 +++++++- 10 files changed, 92 insertions(+), 39 deletions(-) diff --git a/server/src/configs/custom-environment-variables.json b/server/src/configs/custom-environment-variables.json index 970c28d2c..9d440de4e 100644 --- a/server/src/configs/custom-environment-variables.json +++ b/server/src/configs/custom-environment-variables.json @@ -352,6 +352,10 @@ "__name": "MAP_MISC_NO_SCAN_AREA_OVERLAY", "__format": "boolean" }, + "scanAreaMenuHeight": { + "__name": "MAP_MISC_SCAN_AREA_MENU_HEIGHT", + "__format": "number" + }, "permImageDir": "MAP_MISC_PERM_IMAGE_DIR", "permArrayImages": { "__name": "MAP_MISC_PERM_ARRAY_IMAGES", diff --git a/server/src/configs/default.json b/server/src/configs/default.json index 14b2e121a..1b052bf29 100644 --- a/server/src/configs/default.json +++ b/server/src/configs/default.json @@ -143,6 +143,7 @@ "enableUserProfile": true, "enableQuestSetSelector": false, "noScanAreaOverlay": false, + "scanAreaMenuHeight": 400, "permImageDir": "images/perms", "permArrayImages": false, "clientTimeoutMinutes": 30, diff --git a/server/src/graphql/mapTypes.js b/server/src/graphql/mapTypes.js index 8e6762f48..89358869c 100644 --- a/server/src/graphql/mapTypes.js +++ b/server/src/graphql/mapTypes.js @@ -52,6 +52,12 @@ module.exports = gql` features: [Feature] } + type ScanAreasMenu { + name: String + details: Feature + children: [Feature] + } + type Search { id: ID name: String diff --git a/server/src/graphql/resolvers.js b/server/src/graphql/resolvers.js index 0ad7f4371..53a7d11be 100644 --- a/server/src/graphql/resolvers.js +++ b/server/src/graphql/resolvers.js @@ -192,6 +192,19 @@ module.exports = { } return [{ features: [] }] }, + scanAreasMenu: (_, args, { perms, version, req }) => { + if (args.version && args.version !== version) + throw new UserInputError('old_client') + if (!perms) throw new AuthenticationError('session_expired') + + const scanAreas = config.scanAreasMenu[req.headers.host] + ? config.scanAreasMenu[req.headers.host] + : config.scanAreasMenu.main + if (perms?.scanAreas && scanAreas.length) { + return scanAreas + } + return [] + }, search: async (_, args, { Event, perms, version, Db }) => { if (args.version && args.version !== version) throw new UserInputError('old_client') diff --git a/server/src/graphql/typeDefs.js b/server/src/graphql/typeDefs.js index 80ca90aa6..867e79487 100644 --- a/server/src/graphql/typeDefs.js +++ b/server/src/graphql/typeDefs.js @@ -77,6 +77,7 @@ module.exports = gql` version: String ): [ScanCell] scanAreas(version: String): [ScanArea] + scanAreasMenu(version: String): [ScanAreasMenu] search( search: String category: String diff --git a/server/src/services/config.js b/server/src/services/config.js index 32106e96e..2a3974338 100644 --- a/server/src/services/config.js +++ b/server/src/services/config.js @@ -220,6 +220,36 @@ config.scanAreas = { ), } +config.scanAreasMenu = Object.fromEntries( + Object.entries(config.scanAreas).map(([domain, areas]) => { + const parents = { '': { children: [], name: '' } } + areas.features.forEach((feature) => { + if (feature.properties.parent) { + parents[feature.properties.parent] = { + name: feature.properties.parent, + details: areas.features.find( + (area) => area.properties.name === feature.properties.parent, + ), + children: [], + } + } + }) + areas.features.forEach((feature) => { + if (feature.properties.parent) { + parents[feature.properties.parent].children.push(feature) + } else if (!parents[feature.properties.name]) { + parents[''].children.push(feature) + } + }) + Object.values(parents).forEach(({ children }) => { + if (children.length % 2 === 1) { + children.push({ type: 'Feature', properties: { name: '' } }) + } + }) + return [domain, Object.values(parents)] + }), +) + config.api.pvp.leagueObj = Object.fromEntries( config.api.pvp.leagues.map((league) => [league.name, league.cp]), ) diff --git a/src/components/layout/drawer/Areas.jsx b/src/components/layout/drawer/Areas.jsx index e3f2b12c6..512d0dbd9 100644 --- a/src/components/layout/drawer/Areas.jsx +++ b/src/components/layout/drawer/Areas.jsx @@ -6,59 +6,32 @@ import { useMap } from 'react-leaflet' import Utility from '@services/Utility' import Query from '@services/Query' -export default function AreaDropDown({ scanAreasZoom }) { - const { data, loading, error } = useQuery(Query.scanAreas(), { +export default function AreaDropDown({ scanAreaMenuHeight, scanAreasZoom }) { + const { data, loading, error } = useQuery(Query.scanAreasMenu(), { variables: { version: inject.VERSION }, }) const map = useMap() if (loading || error) return null - const areas = React.useMemo(() => { - const parents = { '': { children: [] } } - data.scanAreas[0].features.forEach((feature) => { - if (feature.properties.parent && !parents[feature.properties.parent]) { - parents[feature.properties.parent] = { - details: data.scanAreas[0].features.find( - (area) => area.properties.name === feature.properties.parent, - ), - children: data.scanAreas[0].features.filter( - (area) => area.properties.parent === feature.properties.parent, - ), - } - } else { - parents[''].children.push(feature) - } - }) - if (!Object.keys(parents).length) { - parents[''] = { children: data.scanAreas[0].features } - } - Object.values(parents).forEach(({ children }) => { - if (children.length % 2 === 1) { - children.push({ type: 'Feature', properties: { name: '' } }) - } - }) - return parents - }, []) - return ( - {Object.entries(areas).map(([parent, { details, children }]) => ( + {data?.scanAreasMenu?.map(({ name, details, children }) => ( - {Boolean(parent) && ( + {Boolean(name) && ( - {Utility.getProperName(parent)} + {Utility.getProperName(name)} diff --git a/src/components/layout/drawer/Drawer.jsx b/src/components/layout/drawer/Drawer.jsx index 8ca6426bf..d20a44639 100644 --- a/src/components/layout/drawer/Drawer.jsx +++ b/src/components/layout/drawer/Drawer.jsx @@ -36,7 +36,13 @@ export default function Sidebar({ const ui = useStatic((state) => state.ui) const staticUserSettings = useStatic((state) => state.userSettings) const { - map: { title, scanAreasZoom, noScanAreaOverlay, enableQuestSetSelector }, + map: { + title, + scanAreasZoom, + scanAreaMenuHeight, + noScanAreaOverlay, + enableQuestSetSelector, + }, } = useStatic((state) => state.config) const available = useStatic((s) => s.available) const { t } = useTranslation() @@ -136,7 +142,10 @@ export default function Sidebar({ )} {category === 'scanAreas' && ( - + )} diff --git a/src/services/Query.js b/src/services/Query.js index 57233a313..256301ac9 100644 --- a/src/services/Query.js +++ b/src/services/Query.js @@ -8,7 +8,7 @@ import getAllWeather from './queries/weather' import getAllScanCells from './queries/scanCell' import getAllSubmissionCells from './queries/submissionCells' import { getOne, getAllNests } from './queries/nest' -import getAllScanAreas from './queries/scanAreas' +import { getAllScanAreas, getScanAreasMenu } from './queries/scanAreas' import * as searchIndex from './queries/search' import * as webhookIndex from './queries/webhook' import scanner from './queries/scanner' @@ -122,6 +122,10 @@ export default class Query { return getAllScanAreas } + static scanAreasMenu() { + return getScanAreasMenu + } + static search(category) { switch (category) { case 'raids': diff --git a/src/services/queries/scanAreas.js b/src/services/queries/scanAreas.js index 73092dc1a..ebc64d74c 100644 --- a/src/services/queries/scanAreas.js +++ b/src/services/queries/scanAreas.js @@ -1,6 +1,6 @@ import { gql } from '@apollo/client' -const getAllScanAreas = gql` +export const getAllScanAreas = gql` query ScanAreas($version: String) { scanAreas(version: $version) { type @@ -16,4 +16,16 @@ const getAllScanAreas = gql` } ` -export default getAllScanAreas +export const getScanAreasMenu = gql` + query ScanAreasMenu($version: String) { + scanAreasMenu(version: $version) { + name + details { + properties + } + children { + properties + } + } + } +` From bd5297a586436b8018f7884aa625c119ca0e24c0 Mon Sep 17 00:00:00 2001 From: TurtIeSocks <58572875+TurtIeSocks@users.noreply.github.com> Date: Mon, 20 Jun 2022 22:46:47 -0400 Subject: [PATCH 8/8] Add color to the examples --- server/src/configs/local.example.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/src/configs/local.example.json b/server/src/configs/local.example.json index 05ba899d1..273bec007 100644 --- a/server/src/configs/local.example.json +++ b/server/src/configs/local.example.json @@ -300,12 +300,15 @@ "name": "New York", "lat": 40.7481666, "lon": -74.0174788, - "zoom": 15 + "zoom": 15, + "color": "blue" }, { "name": "California", "lat": 37.1931249, - "lon": -123.7961458 + "lon": -123.7961458, + "color": "orange", + "fillColor": "purple" }, { "name": "San Francisco",