Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion server/src/configs/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
"minZoom": 10,
"maxZoom": 18,
"interactionRangeZoom": 15,
"scanAreasZoom": 12,
"scanAreasZoom": 15,
"scanCellsZoom": 13,
"submissionZoom": 15,
"activeWeatherZoom": 13,
Expand Down
6 changes: 4 additions & 2 deletions server/src/configs/local.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,13 +314,15 @@
"name": "San Francisco",
"lat": 37.79539194255634,
"lon": -122.39333173075096,
"parent": "California"
"parent": "California",
"hidden": false
},
{
"name": "Houston",
"lat": 33.6145517,
"lon": -108.6038347,
"parent": "Texas"
"parent": "Texas",
"domain": "map_2.your_map.com"
}
]
}
23 changes: 13 additions & 10 deletions server/src/graphql/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,17 +168,18 @@ module.exports = {
if (clientV !== serverV) throw new UserInputError('old_client')
if (!perms) throw new AuthenticationError('session_expired')

const scanAreas = config.scanAreas[req.headers.host]
? config.scanAreas[req.headers.host]
: config.scanAreas.main
if (perms?.scanAreas && scanAreas.features.length) {
if (perms?.scanAreas) {
const scanAreas = config.scanAreas[req.headers.host]
? config.scanAreas[req.headers.host]
: config.scanAreas.main
return [
{
...scanAreas,
features: scanAreas.features.filter(
(feature) =>
!perms.areaRestrictions.length ||
perms.areaRestrictions.includes(feature.properties.name),
!feature.properties.hidden &&
(!perms.areaRestrictions.length ||
perms.areaRestrictions.includes(feature.properties.name)),
),
},
]
Expand All @@ -189,10 +190,11 @@ module.exports = {
if (clientV !== serverV) 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) {
if (perms?.scanAreas) {
const scanAreas = config.scanAreasMenu[req.headers.host]
? config.scanAreasMenu[req.headers.host]
: config.scanAreasMenu.main

if (perms.areaRestrictions.length) {
const filtered = scanAreas
.map((parent) => ({
Expand All @@ -203,6 +205,7 @@ module.exports = {
}))
.filter((parent) => parent.children.length)

// Adds new blanks to account for area restrictions trimming some
filtered.forEach(({ children }) => {
if (children.length % 2 === 1) {
children.push({
Expand Down
13 changes: 7 additions & 6 deletions server/src/models/Weather.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,16 @@ module.exports = class Weather extends Model {
!merged.length ||
merged.some(
(area) =>
pointInPolygon(
config.scanAreasObj[area] &&
(pointInPolygon(
point(config.scanAreasObj[area].geometry.coordinates[0][0]),
geojson,
) ||
pointInPolygon(
point([cell.longitude, cell.latitude]),
config.scanAreasObj[area],
) ||
booleanOverlap(geojson, config.scanAreasObj[area]),
pointInPolygon(
point([cell.longitude, cell.latitude]),
config.scanAreasObj[area],
) ||
booleanOverlap(geojson, config.scanAreasObj[area])),
)
return (
hasOverlap && {
Expand Down
2 changes: 1 addition & 1 deletion server/src/services/areas.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const loadAreas = () => {
const normalized = { type: 'FeatureCollection', features: [] }
Object.values(config.scanAreas).forEach((area) => {
if (area?.features.length) {
normalized.features.push(...area.features)
normalized.features.push(...area.features.filter((f) => !f.manual))
}
})
return normalized
Expand Down
75 changes: 44 additions & 31 deletions server/src/services/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,51 +166,54 @@ config.authMethods = [
}
})

const manualGeojson = {
type: 'FeatureCollection',
features: config.manualAreas
.filter((area) =>
['lat', 'lon', 'name'].every((k) => k in area && !area.hidden),
)
.map((area) => {
const { lat, lon, ...rest } = area
return {
type: 'Feature',
properties: {
center: [lat, lon],
manual: true,
...rest,
},
geometry: {
type: 'Polygon',
coordinates: [[[lon, lat]]],
},
}
}),
}

// Load each areas.json
const loadScanPolygons = (fileName) => {
const loadScanPolygons = (fileName, domain) => {
const geojson = fs.existsSync(resolve(`${__dirname}/../configs/${fileName}`))
? JSON.parse(fs.readFileSync(resolve(__dirname, `../configs/${fileName}`)))
: { features: [] }
return {
...geojson,
features: geojson.features
.filter((f) => !f.properties.hidden)
.map((f) => ({
features: [
...manualGeojson.features.filter(
(f) => !f.properties.domain || f.properties.domain === domain,
),
...geojson.features.map((f) => ({
...f,
properties: {
...f.properties,
center: center(f).geometry.coordinates.reverse(),
},
}))
.sort((a, b) => a.properties.name.localeCompare(b.properties.name)),
})),
].sort((a, b) => a.properties.name.localeCompare(b.properties.name)),
}
}

// Check if an areas.json exists
config.scanAreas = {
main: config.manualAreas.length
? {
type: 'FeatureCollection',
features: config.manualAreas
.filter((area) => ['lat', 'lon', 'name'].every((k) => k in area))
.map((area) => {
const { lat, lon, ...rest } = area
return {
type: 'Feature',
properties: {
center: [lat, lon],
manual: true,
...rest,
},
geometry: {
type: 'Polygon',
coordinates: [[[lon, lat]]],
},
}
})
.sort((a, b) => a.properties.name.localeCompare(b.properties.name)),
}
: loadScanPolygons(config.map.geoJsonFileName),
main: loadScanPolygons(config.map.geoJsonFileName),
...Object.fromEntries(
config.multiDomains.map((d) => [
d.general?.geoJsonFileName ? d.domain : 'main',
Expand All @@ -224,7 +227,13 @@ config.scanAreas = {
config.scanAreasMenu = Object.fromEntries(
Object.entries(config.scanAreas).map(([domain, areas]) => {
const parents = { '': { children: [], name: '' } }
areas.features.forEach((feature) => {

const noHidden = {
...areas,
features: areas.features.filter((f) => !f.properties.hidden),
}
// Finds unique parents and determines if the parents have their own properties
noHidden.features.forEach((feature) => {
if (feature.properties.parent) {
parents[feature.properties.parent] = {
name: feature.properties.parent,
Expand All @@ -235,13 +244,17 @@ config.scanAreasMenu = Object.fromEntries(
}
}
})
areas.features.forEach((feature) => {

// Finds the children of each parent
noHidden.features.forEach((feature) => {
if (feature.properties.parent) {
parents[feature.properties.parent].children.push(feature)
} else if (!parents[feature.properties.name]) {
parents[''].children.push(feature)
}
})

// Create blanks for better formatting when there's an odd number of children
Object.values(parents).forEach(({ children }) => {
if (children.length % 2 === 1) {
children.push({
Expand Down
7 changes: 1 addition & 6 deletions server/src/services/functions/getAreaSql.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const config = require('../config')
const areas = require('../areas')

module.exports = function getAreaRestrictionSql(
Expand All @@ -8,11 +7,7 @@ module.exports = function getAreaRestrictionSql(
isMad,
category,
) {
if (
!areaRestrictions?.length &&
(!onlyAreas?.length || config.manualAreas.length)
)
return true
if (!areaRestrictions?.length && !onlyAreas?.length) return true

const cleanUserAreas = onlyAreas.filter((area) => areas.names.includes(area))
const consolidatedAreas = areaRestrictions.length
Expand Down
79 changes: 44 additions & 35 deletions src/components/layout/drawer/AreaTile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@ export default function AreaTile({

const hasAll =
childAreas &&
childAreas.every((c) => scanAreas.filter.areas.includes(c.properties.name))
childAreas.every(
(c) =>
c.properties.manual ||
scanAreas.filter.areas.includes(c.properties.name),
)
const hasSome =
childAreas &&
childAreas.some((c) => scanAreas.filter.areas.includes(c.properties.name))
const hasManual = childAreas
? childAreas.some((c) => c.properties.manual)
: feature.properties.manual
const hasManual =
feature?.properties?.manual || childAreas.every((c) => c.properties.manual)

return (
<Grid
Expand All @@ -43,57 +46,63 @@ export default function AreaTile({
}}
>
<MenuItem
style={{ height: '100%' }}
onClick={() => {
if (feature?.properties) {
if (feature?.properties?.center) {
map.flyTo(
feature.properties.center,
feature.properties.zoom || scanAreasZoom,
)
}
}}
>
<Grid container alignItems="center" justifyContent="space-between">
<Grid
item
// eslint-disable-next-line no-nested-ternary
xs={hasManual ? 12 : name ? 11 : 10}
style={{ textAlign: 'center' }}
>
<Grid container alignItems="center" justifyContent="center">
<Grid item xs={name ? 11 : 10} style={{ textAlign: 'center' }}>
<Typography
variant={name ? 'h6' : 'caption'}
align="center"
style={{ width: '100%', fontWeight: 'bold' }}
style={{
whiteSpace: 'pre-wrap',
}}
>
{name || feature.properties.name ? (
Utility.getProperName(name || feature.properties.name)
.split(' ')
.join('\n')
) : (
<>&nbsp;</>
)}
</Typography>
</Grid>
{!hasManual && (
<Grid item xs={name ? 1 : 2} style={{ textAlign: 'right' }}>
<Checkbox
size="small"
indeterminate={name ? hasSome && !hasAll : false}
checked={
<Grid item xs={name ? 1 : 2} style={{ textAlign: 'right' }}>
<Checkbox
size="small"
indeterminate={name ? hasSome && !hasAll : false}
checked={
name
? hasAll
: scanAreas.filter.areas.includes(feature.properties.name)
}
onChange={() =>
setAreas(
name
? hasAll
: scanAreas.filter.areas.includes(feature.properties.name)
}
onChange={() =>
setAreas(
name
? childAreas.map((c) => c.properties.name)
: feature.properties.name,
allAreas,
name ? hasSome : false,
)
}
disabled={!childAreas.length}
/>
</Grid>
)}
? childAreas.map((c) => c.properties.name)
: feature.properties.name,
allAreas,
name ? hasSome : false,
)
}
style={{
color:
!childAreas.length || hasManual
? feature?.properties?.fillColor ||
feature?.properties?.fill ||
'#212121'
: 'none',
}}
disabled={!childAreas.length || hasManual}
/>
</Grid>
</Grid>
</MenuItem>
</Grid>
Expand Down
10 changes: 6 additions & 4 deletions src/components/layout/drawer/Areas.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { useMemo } from 'react'
import { useQuery } from '@apollo/client'
import { Grid, Button, Paper } from '@material-ui/core'
import { useTranslation } from 'react-i18next'
Expand All @@ -12,10 +12,12 @@ export default function AreaDropDown({ scanAreaMenuHeight, scanAreasZoom }) {
const { t } = useTranslation()
const setAreas = useStore((s) => s.setAreas)

const allAreas = React.useMemo(() => {
const allAreas = useMemo(() => {
if (data?.scanAreasMenu) {
return data.scanAreasMenu.flatMap((parent) =>
parent.children.map((child) => child.properties.name),
parent.children
.filter((child) => !child.properties.manual)
.map((child) => child.properties.name),
)
}
return []
Expand Down Expand Up @@ -52,7 +54,7 @@ export default function AreaDropDown({ scanAreaMenuHeight, scanAreasZoom }) {
<Grid
key={name || ''}
container
alignItems="center"
alignItems="stretch"
justifyContent="center"
>
{name && (
Expand Down
Loading