diff --git a/app/package-lock.json b/app/package-lock.json index 4f4543c08..ce236f06c 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -25,7 +25,6 @@ "maplibre-gl": "^4.4.1", "next": "^14.2.7", "pmtiles": "^3.0.7", - "prettier-airbnb-config": "^1.0.0", "react": "^18", "react-dom": "^18", "react-resizable": "^3.0.5", @@ -46,6 +45,7 @@ "jest": "^29.7.0", "nock": "^13.5.4", "postcss": "^8", + "prettier-airbnb-config": "^1.0.0", "tailwindcss": "^3.4.1", "typescript": "^5" } @@ -10943,6 +10943,7 @@ "version": "1.19.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true, "peer": true, "bin": { "prettier": "bin-prettier.js" @@ -10955,6 +10956,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/prettier-airbnb-config/-/prettier-airbnb-config-1.0.0.tgz", "integrity": "sha512-FsEe38fJftYi19AskzuOWbw8zBnXDcZwv2Uw8BI65ROyK4hE6+iojXVFu+FiYNfrRBL+UZJbl2XGk56Ur2QGsA==", + "dev": true, "peerDependencies": { "prettier": "^1.18.2" } diff --git a/app/src/app/api/sentry-example-api/route.ts b/app/src/app/api/sentry-example-api/route.ts index f486f3d1d..aad6597e8 100644 --- a/app/src/app/api/sentry-example-api/route.ts +++ b/app/src/app/api/sentry-example-api/route.ts @@ -1,9 +1,9 @@ -import { NextResponse } from "next/server"; +import {NextResponse} from 'next/server'; -export const dynamic = "force-dynamic"; +export const dynamic = 'force-dynamic'; // A faulty API route to test Sentry's error monitoring export function GET() { - throw new Error("Sentry Example API Route Error"); - return NextResponse.json({ data: "Testing Sentry Error..." }); + throw new Error('Sentry Example API Route Error'); + return NextResponse.json({data: 'Testing Sentry Error...'}); } diff --git a/app/src/app/components/ContextMenu.tsx b/app/src/app/components/ContextMenu.tsx index ed1a04f88..ecaeea7d9 100644 --- a/app/src/app/components/ContextMenu.tsx +++ b/app/src/app/components/ContextMenu.tsx @@ -1,11 +1,11 @@ -import React from "react"; -import { ContextMenu, Text } from "@radix-ui/themes"; -import { useMapStore } from "@/app/store/mapStore"; +import React from 'react'; +import {ContextMenu, Text} from '@radix-ui/themes'; +import {useMapStore} from '@/app/store/mapStore'; export const MapContextMenu: React.FC = () => { - const mapDocument = useMapStore((state) => state.mapDocument); - const contextMenu = useMapStore((state) => state.contextMenu); - const handleShatter = useMapStore((state) => state.handleShatter); + const mapDocument = useMapStore(state => state.mapDocument); + const contextMenu = useMapStore(state => state.contextMenu); + const handleShatter = useMapStore(state => state.handleShatter); if (!contextMenu) return null; const handleSelect = () => { @@ -27,7 +27,7 @@ export const MapContextMenu: React.FC = () => { // also, if in the future we need the context menu outside of the map, // this sets us up to do that style={{ - position: "fixed", + position: 'fixed', top: contextMenu.y, left: contextMenu.x, }} @@ -39,10 +39,7 @@ export const MapContextMenu: React.FC = () => { )} - + Shatter diff --git a/app/src/app/components/sidebar/BrushSizeSelector.tsx b/app/src/app/components/sidebar/BrushSizeSelector.tsx index e6efa0ebf..d962a0a2f 100644 --- a/app/src/app/components/sidebar/BrushSizeSelector.tsx +++ b/app/src/app/components/sidebar/BrushSizeSelector.tsx @@ -1,5 +1,5 @@ -import { Slider, Flex, Heading, Text } from "@radix-ui/themes"; -import { useMapStore } from "../../store/mapStore"; +import {Slider, Flex, Heading, Text} from '@radix-ui/themes'; +import {useMapStore} from '../../store/mapStore'; /** * BrushSizeSelector @@ -11,22 +11,17 @@ import { useMapStore } from "../../store/mapStore"; * @returns {JSX.Element} The component */ export function BrushSizeSelector() { - const brushSize = useMapStore((state) => state.brushSize); - const setBrushSize = useMapStore((state) => state.setBrushSize); + const brushSize = useMapStore(state => state.brushSize); + const setBrushSize = useMapStore(state => state.setBrushSize); const handleChangeEnd = (value: Array) => { - console.log("the final value size is", value); + console.log('the final value size is', value); setBrushSize(value.length ? value[0] : 0); }; return ( - + Brush Size (30); const [offset, setOffset] = useState(0); - const mapDocument = useMapStore((state) => state.mapDocument); - const mapViews = useMapStore((state) => state.mapViews); - const { isPending, isError, data, error } = mapViews || {}; + const mapDocument = useMapStore(state => state.mapDocument); + const mapViews = useMapStore(state => state.mapViews); + const {isPending, isError, data, error} = mapViews || {}; - const selectedView = data?.find( - (view) => view.gerrydb_table_name === mapDocument?.gerrydb_table - ); + const selectedView = data?.find(view => view.gerrydb_table_name === mapDocument?.gerrydb_table); const handleValueChange = (value: string) => { - console.log("Value changed: ", value); - const selectedDistrictrMap = data?.find((view) => view.name === value); - console.log("Selected view: ", selectedDistrictrMap); + console.log('Value changed: ', value); + const selectedDistrictrMap = data?.find(view => view.name === value); + console.log('Selected view: ', selectedDistrictrMap); if ( !selectedDistrictrMap || selectedDistrictrMap.gerrydb_table_name === mapDocument?.gerrydb_table ) { - console.log("No document or same document"); + console.log('No document or same document'); return; } - console.log("mutating to create new document"); - document.mutate({ gerrydb_table: selectedDistrictrMap.gerrydb_table_name }); + console.log('mutating to create new document'); + document.mutate({gerrydb_table: selectedDistrictrMap.gerrydb_table_name}); }; if (isPending) return
Loading geographies... 🌎
; @@ -34,17 +32,9 @@ export function GerryDBViewSelector() { if (isError) return
Error loading geographies: {error?.message}
; return ( - - - + + + Districtr map options diff --git a/app/src/app/components/sidebar/Layers.tsx b/app/src/app/components/sidebar/Layers.tsx index 7ba84ee49..86b761710 100644 --- a/app/src/app/components/sidebar/Layers.tsx +++ b/app/src/app/components/sidebar/Layers.tsx @@ -1,11 +1,7 @@ -import { Heading, CheckboxGroup, Flex } from "@radix-ui/themes"; -import { useMapStore } from "@/app/store/mapStore"; -import { - COUNTY_LAYER_IDS, - BLOCK_LAYER_ID, - BLOCK_HOVER_LAYER_ID, -} from "../../constants/layers"; -import { toggleLayerVisibility } from "../../utils/helpers"; +import {Heading, CheckboxGroup, Flex} from '@radix-ui/themes'; +import {useMapStore} from '@/app/store/mapStore'; +import {COUNTY_LAYER_IDS, BLOCK_LAYER_ID, BLOCK_HOVER_LAYER_ID} from '../../constants/layers'; +import {toggleLayerVisibility} from '../../utils/helpers'; /** Layers * This component is responsible for rendering the layers that can be toggled @@ -16,10 +12,10 @@ import { toggleLayerVisibility } from "../../utils/helpers"; * - Support tribes and communities */ export default function Layers() { - const mapRef = useMapStore((state) => state.getMapRef()); - const mapDocument = useMapStore((state) => state.mapDocument); - const visibleLayerIds = useMapStore((state) => state.visibleLayerIds); - const updateVisibleLayerIds = useMapStore((state) => state.updateVisibleLayerIds); + const mapRef = useMapStore(state => state.getMapRef()); + const mapDocument = useMapStore(state => state.mapDocument); + const visibleLayerIds = useMapStore(state => state.visibleLayerIds); + const updateVisibleLayerIds = useMapStore(state => state.updateVisibleLayerIds); const toggleLayers = (layerIds: string[]) => { if (!mapRef) return; @@ -35,7 +31,7 @@ export default function Layers() { visibleLayerIds.includes(layerId)) - ? ["1"] - : [] - } + value={COUNTY_LAYER_IDS.every(layerId => visibleLayerIds.includes(layerId)) ? ['1'] : []} > - toggleLayers(COUNTY_LAYER_IDS)} - > + toggleLayers(COUNTY_LAYER_IDS)}> Show county boundaries diff --git a/app/src/app/components/sidebar/PaintByCounty.tsx b/app/src/app/components/sidebar/PaintByCounty.tsx index 4dee72031..88e72afa4 100644 --- a/app/src/app/components/sidebar/PaintByCounty.tsx +++ b/app/src/app/components/sidebar/PaintByCounty.tsx @@ -1,24 +1,21 @@ -import { Box, Text, Checkbox, Flex } from "@radix-ui/themes"; -import { useMapStore } from "@/app/store/mapStore"; -import { COUNTY_LAYER_IDS } from "../../constants/layers"; -import { useState, useEffect } from "react"; -import { - getFeaturesInBbox, - getFeaturesIntersectingCounties, -} from "../../utils/helpers"; +import {Box, Text, Checkbox, Flex} from '@radix-ui/themes'; +import {useMapStore} from '@/app/store/mapStore'; +import {COUNTY_LAYER_IDS} from '../../constants/layers'; +import {useState, useEffect} from 'react'; +import {getFeaturesInBbox, getFeaturesIntersectingCounties} from '../../utils/helpers'; export default function PaintByCounty() { - const mapRef = useMapStore((state) => state.getMapRef()); - const addVisibleLayerIds = useMapStore((state) => state.addVisibleLayerIds); - const setPaintFunction = useMapStore((state) => state.setPaintFunction); + const mapRef = useMapStore(state => state.getMapRef()); + const addVisibleLayerIds = useMapStore(state => state.addVisibleLayerIds); + const setPaintFunction = useMapStore(state => state.setPaintFunction); const [checked, setChecked] = useState(false); useEffect(() => { if (!mapRef) return; if (checked) { - COUNTY_LAYER_IDS.forEach((layerId) => { - mapRef.setLayoutProperty(layerId, "visibility", "visible"); + COUNTY_LAYER_IDS.forEach(layerId => { + mapRef.setLayoutProperty(layerId, 'visibility', 'visible'); }); addVisibleLayerIds(COUNTY_LAYER_IDS); setPaintFunction(getFeaturesIntersectingCounties); @@ -34,7 +31,7 @@ export default function PaintByCounty() { setChecked((prevIsChecked) => !prevIsChecked)} + onClick={() => setChecked(prevIsChecked => !prevIsChecked)} /> Paint by County diff --git a/app/src/app/components/sidebar/RecentMapsModal.tsx b/app/src/app/components/sidebar/RecentMapsModal.tsx index 746f53e49..3226e2b0b 100644 --- a/app/src/app/components/sidebar/RecentMapsModal.tsx +++ b/app/src/app/components/sidebar/RecentMapsModal.tsx @@ -1,6 +1,6 @@ -import { useMapStore } from "@/app/store/mapStore"; -import React from "react"; -import { Cross2Icon, CounterClockwiseClockIcon } from "@radix-ui/react-icons"; +import {useMapStore} from '@/app/store/mapStore'; +import React from 'react'; +import {Cross2Icon, CounterClockwiseClockIcon} from '@radix-ui/react-icons'; import { Button, Flex, @@ -11,25 +11,25 @@ import { TextField, IconButton, RadioCards, -} from "@radix-ui/themes"; -import { usePathname, useSearchParams, useRouter } from "next/navigation"; -import { DocumentObject } from "../../utils/api/apiHandlers"; -type NamedDocumentObject = DocumentObject & { name?: string }; +} from '@radix-ui/themes'; +import {usePathname, useSearchParams, useRouter} from 'next/navigation'; +import {DocumentObject} from '../../utils/api/apiHandlers'; +type NamedDocumentObject = DocumentObject & {name?: string}; export const RecentMapsModal = () => { const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); - const mapDocument = useMapStore((store) => store.mapDocument); - const userMaps = useMapStore((store) => store.userMaps); - const upcertUserMap = useMapStore((store) => store.upcertUserMap); - const setMapDocument = useMapStore((store) => store.setMapDocument); + const mapDocument = useMapStore(store => store.mapDocument); + const userMaps = useMapStore(store => store.userMaps); + const upcertUserMap = useMapStore(store => store.upcertUserMap); + const setMapDocument = useMapStore(store => store.setMapDocument); const [dialogOpen, setDialogOpen] = React.useState(false); const handleMapDocument = (data: NamedDocumentObject) => { setMapDocument(data); const urlParams = new URLSearchParams(searchParams.toString()); - urlParams.set("document_id", data.document_id); - router.push(pathname + "?" + urlParams.toString()); + urlParams.set('document_id', data.document_id); + router.push(pathname + '?' + urlParams.toString()); // close dialog setDialogOpen(false); }; @@ -48,9 +48,7 @@ export const RecentMapsModal = () => { - - Recent Maps - + Recent Maps { - - Map Name - + Map Name Last Updated {/* load */} {/* delete */} @@ -76,7 +72,7 @@ export const RecentMapsModal = () => { + onChange={userMapData => upcertUserMap({ userMapData, userMapDocumentId: userMap.document_id, @@ -98,17 +94,17 @@ const RecentMapsRow: React.FC<{ onSelect: (data: NamedDocumentObject) => void; active: boolean; onChange?: (data?: NamedDocumentObject) => void; -}> = ({ data, onSelect, active, onChange }) => { +}> = ({data, onSelect, active, onChange}) => { const updatedDate = new Date(data.updated_at as string); const formattedData = updatedDate.toLocaleDateString(); const name = data?.name || data.gerrydb_table; const handleChangeName = (name?: string) => { - name?.length && onChange?.({ ...data, name }); + name?.length && onChange?.({...data, name}); }; return ( - + {!!(active && onChange) ? ( @@ -116,7 +112,7 @@ const RecentMapsRow: React.FC<{ placeholder={name} size="3" value={name} - onChange={(e) => handleChangeName(e.target.value)} + onChange={e => handleChangeName(e.target.value)} > ) : ( diff --git a/app/src/app/components/sidebar/ResetMapButton.tsx b/app/src/app/components/sidebar/ResetMapButton.tsx index 4e289b57f..06f8af11b 100644 --- a/app/src/app/components/sidebar/ResetMapButton.tsx +++ b/app/src/app/components/sidebar/ResetMapButton.tsx @@ -1,5 +1,5 @@ -import { useMapStore } from "@/app/store/mapStore"; -import { Button } from "@radix-ui/themes"; +import {useMapStore} from '@/app/store/mapStore'; +import {Button} from '@radix-ui/themes'; export function ResetMapButton() { const mapStore = useMapStore.getState(); @@ -11,7 +11,7 @@ export function ResetMapButton() { }; return ( - ); diff --git a/app/src/app/components/sidebar/Sidebar.tsx b/app/src/app/components/sidebar/Sidebar.tsx index 1c1aed307..4b0fc833a 100644 --- a/app/src/app/components/sidebar/Sidebar.tsx +++ b/app/src/app/components/sidebar/Sidebar.tsx @@ -1,36 +1,33 @@ -import { Box, Flex, Heading } from "@radix-ui/themes"; -import { MapModeSelector } from "./MapModeSelector"; -import { ColorPicker } from "./ColorPicker"; -import { ResetMapButton } from "./ResetMapButton"; -import { GerryDBViewSelector } from "./GerryDBViewSelector"; -import { HorizontalBar } from "./charts/HorizontalBarChart"; -import { useMapStore } from "@/app/store/mapStore"; -import { Tabs, Text } from "@radix-ui/themes"; -import Layers from "./Layers"; -import PaintByCounty from "./PaintByCounty"; -import { BrushSizeSelector } from "./BrushSizeSelector"; +import {Box, Flex, Heading} from '@radix-ui/themes'; +import {MapModeSelector} from './MapModeSelector'; +import {ColorPicker} from './ColorPicker'; +import {ResetMapButton} from './ResetMapButton'; +import {GerryDBViewSelector} from './GerryDBViewSelector'; +import {HorizontalBar} from './charts/HorizontalBarChart'; +import {useMapStore} from '@/app/store/mapStore'; +import {Tabs, Text} from '@radix-ui/themes'; +import Layers from './Layers'; +import PaintByCounty from './PaintByCounty'; +import {BrushSizeSelector} from './BrushSizeSelector'; export default function SidebarComponent() { - const activeTool = useMapStore((state) => state.activeTool); + const activeTool = useMapStore(state => state.activeTool); return ( - + Districtr - {activeTool === "brush" || activeTool === "eraser" ? ( + {activeTool === 'brush' || activeTool === 'eraser' ? (
- {" "} + {' '}
) : null} - {activeTool === "brush" ? ( + {activeTool === 'brush' ? (
diff --git a/app/src/app/components/sidebar/charts/HorizontalBarChart.tsx b/app/src/app/components/sidebar/charts/HorizontalBarChart.tsx index 8c4d609ba..74ed8b4da 100644 --- a/app/src/app/components/sidebar/charts/HorizontalBarChart.tsx +++ b/app/src/app/components/sidebar/charts/HorizontalBarChart.tsx @@ -1,24 +1,16 @@ -import { useMapStore } from "@/app/store/mapStore"; -import { Card, Flex, Heading, Text } from "@radix-ui/themes"; -import { - BarChart, - Bar, - ResponsiveContainer, - Tooltip, - XAxis, - YAxis, - Cell, -} from "recharts"; -import { colorScheme } from "@/app/constants/colors"; +import {useMapStore} from '@/app/store/mapStore'; +import {Card, Flex, Heading, Text} from '@radix-ui/themes'; +import {BarChart, Bar, ResponsiveContainer, Tooltip, XAxis, YAxis, Cell} from 'recharts'; +import {colorScheme} from '@/app/constants/colors'; type TooltipInput = { active?: boolean; - payload?: [{ payload: { total_pop: number; zone: number } }]; + payload?: [{payload: {total_pop: number; zone: number}}]; }; -const numberFormat = new Intl.NumberFormat("en-US"); +const numberFormat = new Intl.NumberFormat('en-US'); -const CustomTooltip = ({ active, payload: items }: TooltipInput) => { +const CustomTooltip = ({active, payload: items}: TooltipInput) => { if (active && items && items.length) { const payload = items[0].payload; return ( @@ -31,7 +23,7 @@ const CustomTooltip = ({ active, payload: items }: TooltipInput) => { }; export const HorizontalBar = () => { - const mapMetrics = useMapStore((state) => state.mapMetrics); + const mapMetrics = useMapStore(state => state.mapMetrics); if (mapMetrics?.isPending) { return
Loading...
; @@ -60,18 +52,12 @@ export const HorizontalBar = () => { height={colorScheme.length * 18} minHeight="200px" > - + numberFormat.format(value)} + domain={[0, 'maxData']} + tickFormatter={value => numberFormat.format(value)} /> } /> @@ -79,10 +65,7 @@ export const HorizontalBar = () => { {mapMetrics.data .sort((a, b) => a.zone - b.zone) .map((entry, index) => ( - + ))} diff --git a/app/src/app/constants/colors.ts b/app/src/app/constants/colors.ts index d4249155b..754cc9e44 100644 --- a/app/src/app/constants/colors.ts +++ b/app/src/app/constants/colors.ts @@ -25,49 +25,49 @@ import { mint, lime, sky, -} from "@radix-ui/colors"; +} from '@radix-ui/colors'; export const colorScheme = [ - "#0099cd", - "#ffca5d", - "#00cd99", - "#99cd00", - "#cd0099", - "#aa44ef", // lighter, req from San Diego + '#0099cd', + '#ffca5d', + '#00cd99', + '#99cd00', + '#cd0099', + '#aa44ef', // lighter, req from San Diego // Color brewer: - "#8dd3c7", - "#bebada", - "#fb8072", - "#80b1d3", - "#fdb462", - "#b3de69", - "#fccde5", - "#bc80bd", - "#ccebc5", - "#ffed6f", - "#ffffb3", + '#8dd3c7', + '#bebada', + '#fb8072', + '#80b1d3', + '#fdb462', + '#b3de69', + '#fccde5', + '#bc80bd', + '#ccebc5', + '#ffed6f', + '#ffffb3', // other color brewer scheme: - "#a6cee3", - "#1f78b4", - "#b2df8a", - "#33a02c", - "#fb9a99", - "#e31a1c", - "#fdbf6f", - "#ff7f00", - "#cab2d6", - "#6a3d9a", - "#b15928", + '#a6cee3', + '#1f78b4', + '#b2df8a', + '#33a02c', + '#fb9a99', + '#e31a1c', + '#fdbf6f', + '#ff7f00', + '#cab2d6', + '#6a3d9a', + '#b15928', // random material design colors: - "#64ffda", - "#00B8D4", - "#A1887F", - "#76FF03", - "#DCE775", - "#B388FF", - "#FF80AB", - "#D81B60", - "#26A69A", - "#FFEA00", - "#6200EA", + '#64ffda', + '#00B8D4', + '#A1887F', + '#76FF03', + '#DCE775', + '#B388FF', + '#FF80AB', + '#D81B60', + '#26A69A', + '#FFEA00', + '#6200EA', ]; diff --git a/app/src/app/constants/layers.ts b/app/src/app/constants/layers.ts index 8924620b7..79b3404a2 100644 --- a/app/src/app/constants/layers.ts +++ b/app/src/app/constants/layers.ts @@ -1,77 +1,56 @@ -import { - ExpressionSpecification, - FilterSpecification, - LayerSpecification, -} from "maplibre-gl"; -import { Map } from "maplibre-gl"; -import { getBlocksSource } from "./sources"; -import { DocumentObject } from "../utils/api/apiHandlers"; -import { MapStore, useMapStore } from "../store/mapStore"; -import { colorScheme } from "./colors"; - -export const BLOCK_SOURCE_ID = "blocks"; -export const BLOCK_LAYER_ID = "blocks"; -export const BLOCK_LAYER_ID_CHILD = "blocks-child"; +import {ExpressionSpecification, FilterSpecification, LayerSpecification} from 'maplibre-gl'; +import {Map} from 'maplibre-gl'; +import {getBlocksSource} from './sources'; +import {DocumentObject} from '../utils/api/apiHandlers'; +import {MapStore, useMapStore} from '../store/mapStore'; +import {colorScheme} from './colors'; + +export const BLOCK_SOURCE_ID = 'blocks'; +export const BLOCK_LAYER_ID = 'blocks'; +export const BLOCK_LAYER_ID_CHILD = 'blocks-child'; export const BLOCK_HOVER_LAYER_ID = `${BLOCK_LAYER_ID}-hover`; export const BLOCK_HOVER_LAYER_ID_CHILD = `${BLOCK_LAYER_ID_CHILD}-hover`; -export const INTERACTIVE_LAYERS = [ - BLOCK_HOVER_LAYER_ID, - BLOCK_HOVER_LAYER_ID_CHILD, -]; +export const INTERACTIVE_LAYERS = [BLOCK_HOVER_LAYER_ID, BLOCK_HOVER_LAYER_ID_CHILD]; export const PARENT_LAYERS = [BLOCK_LAYER_ID, BLOCK_HOVER_LAYER_ID]; export const CHILD_LAYERS = [BLOCK_LAYER_ID_CHILD, BLOCK_HOVER_LAYER_ID_CHILD]; export const DEFAULT_PAINT_STYLE: ExpressionSpecification = [ - "case", - ["boolean", ["feature-state", "hover"], false], - "#FF0000", - "#000000", + 'case', + ['boolean', ['feature-state', 'hover'], false], + '#FF0000', + '#000000', ]; -export const COUNTY_LAYER_IDS: string[] = [ - "counties_boundary", - "counties_labels", -]; +export const COUNTY_LAYER_IDS: string[] = ['counties_boundary', 'counties_labels']; -export const LABELS_BREAK_LAYER_ID = "places_subplace"; +export const LABELS_BREAK_LAYER_ID = 'places_subplace'; -const colorStyleBaseline: any[] = ["case"]; +const colorStyleBaseline: any[] = ['case']; -export const ZONE_ASSIGNMENT_STYLE_DYNAMIC = colorScheme.reduce( - (val, color, i) => { - val.push(["==", ["feature-state", "zone"], i + 1], color); // 1-indexed per mapStore.ts - return val; - }, - colorStyleBaseline -); -ZONE_ASSIGNMENT_STYLE_DYNAMIC.push("#cecece"); +export const ZONE_ASSIGNMENT_STYLE_DYNAMIC = colorScheme.reduce((val, color, i) => { + val.push(['==', ['feature-state', 'zone'], i + 1], color); // 1-indexed per mapStore.ts + return val; +}, colorStyleBaseline); +ZONE_ASSIGNMENT_STYLE_DYNAMIC.push('#cecece'); // cast the above as an ExpressionSpecification // @ts-ignore -export const ZONE_ASSIGNMENT_STYLE: ExpressionSpecification = - ZONE_ASSIGNMENT_STYLE_DYNAMIC; +export const ZONE_ASSIGNMENT_STYLE: ExpressionSpecification = ZONE_ASSIGNMENT_STYLE_DYNAMIC; -export function getLayerFilter( - layerId: string, - _shatterIds?: MapStore["shatterIds"] -) { +export function getLayerFilter(layerId: string, _shatterIds?: MapStore['shatterIds']) { const shatterIds = _shatterIds || useMapStore.getState().shatterIds; const isChildLayer = CHILD_LAYERS.includes(layerId); const ids = isChildLayer ? shatterIds.children : shatterIds.parents; const cleanIds = Boolean(ids) ? Array.from(ids) : []; - const filterBase: FilterSpecification = [ - "in", - ["get", "path"], - ["literal", cleanIds], - ]; + const filterBase: FilterSpecification = ['in', ['get', 'path'], ['literal', cleanIds]]; if (isChildLayer) { return filterBase; } - const parentFilter: FilterSpecification = ["!", filterBase]; + const parentFilter: FilterSpecification = ['!', filterBase]; return parentFilter; } @@ -83,20 +62,15 @@ export function getBlocksLayerSpecification( return { id: layerId, source: BLOCK_SOURCE_ID, - "source-layer": sourceLayer, - type: "line", + 'source-layer': sourceLayer, + type: 'line', layout: { - visibility: "visible", + visibility: 'visible', }, filter: getLayerFilter(layerId), paint: { - "line-opacity": [ - "case", - ["boolean", ["feature-state", "hover"], false], - 1, - 0.8, - ], - "line-color": "#cecece", + 'line-opacity': ['case', ['boolean', ['feature-state', 'hover'], false], 1, 0.8], + 'line-color': '#cecece', }, }; } @@ -108,58 +82,58 @@ export function getBlocksHoverLayerSpecification( return { id: layerId, source: BLOCK_SOURCE_ID, - "source-layer": sourceLayer, - type: "fill", + 'source-layer': sourceLayer, + type: 'fill', layout: { - visibility: "visible", + visibility: 'visible', }, filter: getLayerFilter(layerId), paint: { - "fill-opacity": [ - "case", + 'fill-opacity': [ + 'case', // zone is selected and hover is true and hover is not null [ - "all", + 'all', // @ts-ignore - ["!", ["==", ["feature-state", "zone"], null]], //< desired behavior but typerror + ['!', ['==', ['feature-state', 'zone'], null]], //< desired behavior but typerror [ - "all", + 'all', // @ts-ignore - ["!", ["==", ["feature-state", "hover"], null]], //< desired behavior but typerror - ["boolean", ["feature-state", "hover"], true], + ['!', ['==', ['feature-state', 'hover'], null]], //< desired behavior but typerror + ['boolean', ['feature-state', 'hover'], true], ], ], 0.9, // zone is selected and hover is false, and hover is not null [ - "all", + 'all', // @ts-ignore - ["!", ["==", ["feature-state", "zone"], null]], //< desired behavior but typerror + ['!', ['==', ['feature-state', 'zone'], null]], //< desired behavior but typerror [ - "all", + 'all', // @ts-ignore - ["!", ["==", ["feature-state", "hover"], null]], //< desired behavior but typerror - ["boolean", ["feature-state", "hover"], false], + ['!', ['==', ['feature-state', 'hover'], null]], //< desired behavior but typerror + ['boolean', ['feature-state', 'hover'], false], ], ], 0.7, // zone is selected, fallback, regardless of hover state // @ts-ignore - ["!", ["==", ["feature-state", "zone"], null]], //< desired behavior but typerror + ['!', ['==', ['feature-state', 'zone'], null]], //< desired behavior but typerror 0.7, // hover is true, fallback, regardless of zone state - ["boolean", ["feature-state", "hover"], false], + ['boolean', ['feature-state', 'hover'], false], 0.6, 0.2, ], - "fill-color": ZONE_ASSIGNMENT_STYLE || "#000000", + 'fill-color': ZONE_ASSIGNMENT_STYLE || '#000000', }, }; } const addBlockLayers = (map: Map | null, mapDocument: DocumentObject) => { if (!map || !mapDocument.tiles_s3_path) { - console.log("map or mapDocument not ready", mapDocument); + console.log('map or mapDocument not ready', mapDocument); return; } const blockSource = getBlocksSource(mapDocument.tiles_s3_path); @@ -170,30 +144,21 @@ const addBlockLayers = (map: Map | null, mapDocument: DocumentObject) => { LABELS_BREAK_LAYER_ID ); map?.addLayer( - getBlocksHoverLayerSpecification( - mapDocument.parent_layer, - BLOCK_HOVER_LAYER_ID - ), + getBlocksHoverLayerSpecification(mapDocument.parent_layer, BLOCK_HOVER_LAYER_ID), LABELS_BREAK_LAYER_ID ); if (mapDocument.child_layer) { map?.addLayer( - getBlocksLayerSpecification( - mapDocument.child_layer, - BLOCK_LAYER_ID_CHILD - ), + getBlocksLayerSpecification(mapDocument.child_layer, BLOCK_LAYER_ID_CHILD), LABELS_BREAK_LAYER_ID ); map?.addLayer( - getBlocksHoverLayerSpecification( - mapDocument.child_layer, - BLOCK_HOVER_LAYER_ID_CHILD - ), + getBlocksHoverLayerSpecification(mapDocument.child_layer, BLOCK_HOVER_LAYER_ID_CHILD), LABELS_BREAK_LAYER_ID ); } - useMapStore.getState().setMapRenderingState("loaded"); - + useMapStore.getState().setMapRenderingState('loaded'); + // update map bounds based on document extent useMapStore.getState().setMapOptions({ bounds: mapDocument.extent as [number, number, number, number], @@ -205,7 +170,7 @@ export function removeBlockLayers(map: Map | null) { if (!map) { return; } - useMapStore.getState().setMapRenderingState("loading"); + useMapStore.getState().setMapRenderingState('loading'); if (map.getLayer(BLOCK_LAYER_ID)) { map.removeLayer(BLOCK_LAYER_ID); } @@ -223,4 +188,4 @@ export function removeBlockLayers(map: Map | null) { } } -export { addBlockLayers }; +export {addBlockLayers}; diff --git a/app/src/app/constants/sources.ts b/app/src/app/constants/sources.ts index e4ef23318..d814b37e4 100644 --- a/app/src/app/constants/sources.ts +++ b/app/src/app/constants/sources.ts @@ -1,11 +1,9 @@ -import { VectorSourceSpecification } from "maplibre-gl"; +import {VectorSourceSpecification} from 'maplibre-gl'; -export function getBlocksSource( - layer_subpath: string -): VectorSourceSpecification { +export function getBlocksSource(layer_subpath: string): VectorSourceSpecification { return { - type: "vector", + type: 'vector', url: `pmtiles://${process.env.NEXT_PUBLIC_S3_BUCKET_URL}/${layer_subpath}`, - promoteId: "path", + promoteId: 'path', }; } diff --git a/app/src/app/global-error.tsx b/app/src/app/global-error.tsx index 9bda5feef..58469cc07 100644 --- a/app/src/app/global-error.tsx +++ b/app/src/app/global-error.tsx @@ -1,10 +1,10 @@ -"use client"; +'use client'; -import * as Sentry from "@sentry/nextjs"; -import NextError from "next/error"; -import { useEffect } from "react"; +import * as Sentry from '@sentry/nextjs'; +import NextError from 'next/error'; +import {useEffect} from 'react'; -export default function GlobalError({ error }: { error: Error & { digest?: string } }) { +export default function GlobalError({error}: {error: Error & {digest?: string}}) { useEffect(() => { Sentry.captureException(error); }, [error]); @@ -20,4 +20,4 @@ export default function GlobalError({ error }: { error: Error & { digest?: strin ); -} \ No newline at end of file +} diff --git a/app/src/app/map/page.tsx b/app/src/app/map/page.tsx index 916ac5d76..a2d3592c5 100644 --- a/app/src/app/map/page.tsx +++ b/app/src/app/map/page.tsx @@ -1,13 +1,12 @@ -"use client"; -import React from "react"; -import { MapContextMenu } from "../components/ContextMenu"; -import { MapComponent } from "../components/Map"; -import SidebarComponent from "../components/sidebar/Sidebar"; -import { QueryClientProvider } from "@tanstack/react-query"; -import { queryClient } from "../utils/api/queryClient"; +'use client'; +import React from 'react'; +import {MapContextMenu} from '../components/ContextMenu'; +import {MapComponent} from '../components/Map'; +import SidebarComponent from '../components/sidebar/Sidebar'; +import {QueryClientProvider} from '@tanstack/react-query'; +import {queryClient} from '../utils/api/queryClient'; export default function Map() { - if (queryClient) { return ( diff --git a/app/src/app/page.tsx b/app/src/app/page.tsx index 1f1f92158..c6b60f8bb 100644 --- a/app/src/app/page.tsx +++ b/app/src/app/page.tsx @@ -1,9 +1,8 @@ -"use client"; -import { MapComponent } from "./components/Map"; -import SidebarComponent from "./components/sidebar/Sidebar"; -import { QueryClientProvider } from "@tanstack/react-query"; -import { queryClient } from "./utils/api/queryClient"; - +'use client'; +import {MapComponent} from './components/Map'; +import SidebarComponent from './components/sidebar/Sidebar'; +import {QueryClientProvider} from '@tanstack/react-query'; +import {queryClient} from './utils/api/queryClient'; export default function Home() { return ( diff --git a/app/src/app/sentry-example-page/page.tsx b/app/src/app/sentry-example-page/page.tsx index 88914e7d1..7f2d2bfcd 100644 --- a/app/src/app/sentry-example-page/page.tsx +++ b/app/src/app/sentry-example-page/page.tsx @@ -1,7 +1,7 @@ -"use client"; +'use client'; -import Head from "next/head"; -import * as Sentry from "@sentry/nextjs"; +import Head from 'next/head'; +import * as Sentry from '@sentry/nextjs'; export default function Page() { return ( @@ -13,17 +13,17 @@ export default function Page() {
-

+

{ - await Sentry.startSpan({ - name: 'Example Frontend Span', - op: 'test' - }, async () => { - const res = await fetch("/api/sentry-example-api"); - if (!res.ok) { - throw new Error("Sentry Example Frontend Error"); + await Sentry.startSpan( + { + name: 'Example Frontend Span', + op: 'test', + }, + async () => { + const res = await fetch('/api/sentry-example-api'); + if (!res.ok) { + throw new Error('Sentry Example Frontend Error'); + } } - }); + ); }} > Throw error!

- Next, look for the error on the{" "} - Issues Page. + Next, look for the error on the{' '} + + Issues Page + + .

-

- For more information, see{" "} +

+ For more information, see{' '} https://docs.sentry.io/platforms/javascript/guides/nextjs/ diff --git a/app/src/app/store/mapEditSubs.ts b/app/src/app/store/mapEditSubs.ts index 1967b34a4..0599aee99 100644 --- a/app/src/app/store/mapEditSubs.ts +++ b/app/src/app/store/mapEditSubs.ts @@ -1,24 +1,12 @@ -import { debounce } from "lodash"; -import { - Assignment, - FormatAssignments, - getAssignments, -} from "../utils/api/apiHandlers"; -import { patchUpdates } from "../utils/api/mutations"; -import { useMapStore as _useMapStore, MapStore } from "./mapStore"; -import { shallowCompareArray } from "../utils/helpers"; -import { updateAssignments } from "../utils/api/queries"; +import {debounce} from 'lodash'; +import {Assignment, FormatAssignments, getAssignments} from '../utils/api/apiHandlers'; +import {patchUpdates} from '../utils/api/mutations'; +import {useMapStore as _useMapStore, MapStore} from './mapStore'; +import {shallowCompareArray} from '../utils/helpers'; +import {updateAssignments} from '../utils/api/queries'; -const zoneUpdates = ({ - getMapRef, - zoneAssignments, - appLoadingState, -}: Partial) => { - if ( - getMapRef?.() && - (zoneAssignments?.size) && - appLoadingState === "loaded" - ) { +const zoneUpdates = ({getMapRef, zoneAssignments, appLoadingState}: Partial) => { + if (getMapRef?.() && zoneAssignments?.size && appLoadingState === 'loaded') { const assignments = FormatAssignments(); patchUpdates.mutate(assignments); } @@ -30,24 +18,43 @@ type zoneSubState = [ MapStore['zoneAssignments'], MapStore['appLoadingState'], MapStore['mapRenderingState'] -] +]; export const getMapEditSubs = (useMapStore: typeof _useMapStore) => { const sendZonesOnMapRefSub = useMapStore.subscribe( - (state) => [state.getMapRef, state.zoneAssignments, state.appLoadingState, state.mapRenderingState], - ([getMapRef, zoneAssignments, appLoadingState, mapRenderingState], [ _prevMapRef, _prevZoneAssignments, prevAppLoadingState, prevMapRenderingState]) => { - const previousNotLoaded = [appLoadingState, mapRenderingState, prevAppLoadingState, prevMapRenderingState].some(state => state !== 'loaded') + state => [ + state.getMapRef, + state.zoneAssignments, + state.appLoadingState, + state.mapRenderingState, + ], + ( + [getMapRef, zoneAssignments, appLoadingState, mapRenderingState], + [_prevMapRef, _prevZoneAssignments, prevAppLoadingState, prevMapRenderingState] + ) => { + const previousNotLoaded = [ + appLoadingState, + mapRenderingState, + prevAppLoadingState, + prevMapRenderingState, + ].some(state => state !== 'loaded'); if (!getMapRef() || previousNotLoaded) { - return + return; } - console.log("!!!SENDING UPDATES", appLoadingState, mapRenderingState, prevAppLoadingState, prevMapRenderingState) - debouncedZoneUpdate({ getMapRef, zoneAssignments, appLoadingState }); + console.log( + '!!!SENDING UPDATES', + appLoadingState, + mapRenderingState, + prevAppLoadingState, + prevMapRenderingState + ); + debouncedZoneUpdate({getMapRef, zoneAssignments, appLoadingState}); }, - { equalityFn: shallowCompareArray} + {equalityFn: shallowCompareArray} ); const fetchAssignmentsSub = useMapStore.subscribe( - (state) => state.mapDocument, - (mapDocument) => mapDocument && updateAssignments(mapDocument) + state => state.mapDocument, + mapDocument => mapDocument && updateAssignments(mapDocument) ); return [sendZonesOnMapRefSub, fetchAssignmentsSub]; diff --git a/app/src/app/store/mapRenderSubs.ts b/app/src/app/store/mapRenderSubs.ts index 75eb6897b..9b906c349 100644 --- a/app/src/app/store/mapRenderSubs.ts +++ b/app/src/app/store/mapRenderSubs.ts @@ -5,20 +5,20 @@ import { PARENT_LAYERS, CHILD_LAYERS, getLayerFilter, -} from "@constants/layers"; +} from '@constants/layers'; import { ColorZoneAssignmentsState, colorZoneAssignments, shallowCompareArray, -} from "../utils/helpers"; -import { useMapStore as _useMapStore, MapStore } from "@store/mapStore"; -import { getFeatureUnderCursor } from "@utils/helpers"; +} from '../utils/helpers'; +import {useMapStore as _useMapStore, MapStore} from '@store/mapStore'; +import {getFeatureUnderCursor} from '@utils/helpers'; export const getRenderSubscriptions = (useMapStore: typeof _useMapStore) => { const addLayerSubMapDocument = useMapStore.subscribe< - [MapStore["mapDocument"], MapStore["getMapRef"]] + [MapStore['mapDocument'], MapStore['getMapRef']] >( - (state) => [state.mapDocument, state.getMapRef], + state => [state.mapDocument, state.getMapRef], ([mapDocument, getMapRef]) => { const mapStore = useMapStore.getState(); const mapRef = getMapRef(); @@ -27,23 +27,19 @@ export const getRenderSubscriptions = (useMapStore: typeof _useMapStore) => { mapStore.addVisibleLayerIds([BLOCK_LAYER_ID, BLOCK_HOVER_LAYER_ID]); } }, - { equalityFn: shallowCompareArray }, + {equalityFn: shallowCompareArray} ); const _shatterMapSideEffectRender = useMapStore.subscribe< - [ - MapStore["shatterIds"], - MapStore["getMapRef"], - MapStore["mapRenderingState"], - ] + [MapStore['shatterIds'], MapStore['getMapRef'], MapStore['mapRenderingState']] >( - (state) => [state.shatterIds, state.getMapRef, state.mapRenderingState], + state => [state.shatterIds, state.getMapRef, state.mapRenderingState], ([shatterIds, getMapRef, mapRenderingState]) => { const state = useMapStore.getState(); const mapRef = getMapRef(); const setMapLock = state.setMapLock; - if (!mapRef || mapRenderingState !== "loaded") { + if (!mapRef || mapRenderingState !== 'loaded') { return; } @@ -51,20 +47,20 @@ export const getRenderSubscriptions = (useMapStore: typeof _useMapStore) => { if (state.mapDocument?.child_layer) layersToFilter.push(...CHILD_LAYERS); - layersToFilter.forEach((layerId) => - mapRef.setFilter(layerId, getLayerFilter(layerId, shatterIds)), + layersToFilter.forEach(layerId => + mapRef.setFilter(layerId, getLayerFilter(layerId, shatterIds)) ); - mapRef.once("render", () => { + mapRef.once('render', () => { setMapLock(false); console.log(`Unlocked at`, performance.now()); }); }, - { equalityFn: shallowCompareArray }, + {equalityFn: shallowCompareArray} ); const _hoverMapSideEffectRender = useMapStore.subscribe( - (state) => state.hoverFeatures, + state => state.hoverFeatures, (hoverFeatures, previousHoverFeatures) => { const mapRef = useMapStore.getState().getMapRef(); @@ -72,56 +68,55 @@ export const getRenderSubscriptions = (useMapStore: typeof _useMapStore) => { return; } - previousHoverFeatures.forEach((feature) => { - mapRef.setFeatureState(feature, { hover: false }); + previousHoverFeatures.forEach(feature => { + mapRef.setFeatureState(feature, {hover: false}); }); - hoverFeatures.forEach((feature) => { - mapRef.setFeatureState(feature, { hover: true }); + hoverFeatures.forEach(feature => { + mapRef.setFeatureState(feature, {hover: true}); }); - }, + } ); - const _zoneAssignmentMapSideEffectRender = - useMapStore.subscribe( - (state) => [ - state.zoneAssignments, - state.mapDocument, - state.getMapRef, - state.shatterIds, - state.appLoadingState, - state.mapRenderingState, - ], - (curr, prev) => colorZoneAssignments(curr, prev), - { equalityFn: shallowCompareArray }, - ); + const _zoneAssignmentMapSideEffectRender = useMapStore.subscribe( + state => [ + state.zoneAssignments, + state.mapDocument, + state.getMapRef, + state.shatterIds, + state.appLoadingState, + state.mapRenderingState, + ], + (curr, prev) => colorZoneAssignments(curr, prev), + {equalityFn: shallowCompareArray} + ); - const _updateMapCursor = useMapStore.subscribe( - (state) => state.activeTool, - (activeTool) => { + const _updateMapCursor = useMapStore.subscribe( + state => state.activeTool, + activeTool => { const mapRef = useMapStore.getState().getMapRef(); if (!mapRef) return; let cursor; switch (activeTool) { - case "pan": - cursor = ""; + case 'pan': + cursor = ''; break; - case "brush": - cursor = "pointer"; + case 'brush': + cursor = 'pointer'; break; - case "eraser": - cursor = "pointer"; + case 'eraser': + cursor = 'pointer'; break; - case "shatter": - cursor = "crosshair"; + case 'shatter': + cursor = 'crosshair'; useMapStore.getState().setPaintFunction(getFeatureUnderCursor); break; default: - cursor = ""; + cursor = ''; } mapRef.getCanvas().style.cursor = cursor; - }, + } ); return [ diff --git a/app/src/app/store/metricsSubs.ts b/app/src/app/store/metricsSubs.ts index 9bf573106..25a8c7713 100644 --- a/app/src/app/store/metricsSubs.ts +++ b/app/src/app/store/metricsSubs.ts @@ -1,17 +1,14 @@ -import { updateMapMetrics } from "../utils/api/queries"; -import { useMapStore as _useMapStore } from "./mapStore"; +import {updateMapMetrics} from '../utils/api/queries'; +import {useMapStore as _useMapStore} from './mapStore'; export const getMapMetricsSubs = (useMapStore: typeof _useMapStore) => { - const mapMetricsSub = useMapStore.subscribe( - (state) => state.mapDocument, - (mapDocument) => { + state => state.mapDocument, + mapDocument => { if (mapDocument) { updateMapMetrics(mapDocument); } } ); - return [ - mapMetricsSub - ] -} + return [mapMetricsSub]; +}; diff --git a/app/src/app/store/persistConfig.ts b/app/src/app/store/persistConfig.ts index c7f10baf7..163e3cac2 100644 --- a/app/src/app/store/persistConfig.ts +++ b/app/src/app/store/persistConfig.ts @@ -1,12 +1,10 @@ -import { PersistOptions } from "zustand/middleware" -import { MapStore } from "./mapStore" - +import {PersistOptions} from 'zustand/middleware'; +import {MapStore} from './mapStore'; export const persistOptions: PersistOptions> = { - name: 'districtr-persistrictr', + name: 'districtr-persistrictr', version: 0, - partialize: (state) => ({ - userMaps: state.userMaps + partialize: state => ({ + userMaps: state.userMaps, }), - -} +}; diff --git a/app/src/app/utils/api/apiHandlers.ts b/app/src/app/utils/api/apiHandlers.ts index 27c899f88..377251532 100644 --- a/app/src/app/utils/api/apiHandlers.ts +++ b/app/src/app/utils/api/apiHandlers.ts @@ -1,19 +1,16 @@ -import axios from "axios"; -import "maplibre-gl"; -import { useMapStore } from "@/app/store/mapStore"; +import axios from 'axios'; +import 'maplibre-gl'; +import {useMapStore} from '@/app/store/mapStore'; export const FormatAssignments = () => { - const assignments = Array.from( - useMapStore.getState().zoneAssignments.entries() - ).map( + const assignments = Array.from(useMapStore.getState().zoneAssignments.entries()).map( // @ts-ignore ([geo_id, zone]: [string, number]): { document_id: string; geo_id: string; zone: number; } => ({ - document_id: - useMapStore.getState().mapDocument?.document_id.toString() ?? "", + document_id: useMapStore.getState().mapDocument?.document_id.toString() ?? '', geo_id, zone, }) @@ -76,14 +73,14 @@ export interface DocumentCreate { gerrydb_table: string; } -export const createMapDocument: ( +export const createMapDocument: (document: DocumentCreate) => Promise = async ( document: DocumentCreate -) => Promise = async (document: DocumentCreate) => { +) => { return await axios .post(`${process.env.NEXT_PUBLIC_API_URL}/api/create_document`, { gerrydb_table: document.gerrydb_table, }) - .then((res) => { + .then(res => { return res.data; }); }; @@ -93,33 +90,31 @@ export const createMapDocument: ( * @param document_id - string, the document id * @returns Promise */ -export const getDocument: ( +export const getDocument: (document_id: string) => Promise = async ( document_id: string -) => Promise = async (document_id: string) => { +) => { if (document_id) { return await axios .get(`${process.env.NEXT_PUBLIC_API_URL}/api/document/${document_id}`) - .then((res) => { + .then(res => { return res.data; }); } else { - throw new Error("No document id found"); + throw new Error('No document id found'); } }; export const getAssignments: ( mapDocument: DocumentObject -) => Promise = async (mapDocument) => { +) => Promise = async mapDocument => { if (mapDocument) { return await axios - .get( - `${process.env.NEXT_PUBLIC_API_URL}/api/get_assignments/${mapDocument.document_id}` - ) - .then((res) => { + .get(`${process.env.NEXT_PUBLIC_API_URL}/api/get_assignments/${mapDocument.document_id}`) + .then(res => { return res.data; }); } else { - throw new Error("No document provided"); + throw new Error('No document provided'); } }; @@ -142,17 +137,15 @@ export interface ZonePopulation { */ export const getZonePopulations: ( mapDocument: DocumentObject -) => Promise = async (mapDocument) => { +) => Promise = async mapDocument => { if (mapDocument) { return await axios - .get( - `${process.env.NEXT_PUBLIC_API_URL}/api/document/${mapDocument.document_id}/total_pop` - ) - .then((res) => { + .get(`${process.env.NEXT_PUBLIC_API_URL}/api/document/${mapDocument.document_id}/total_pop`) + .then(res => { return res.data; }); } else { - throw new Error("No document provided"); + throw new Error('No document provided'); } }; @@ -167,10 +160,8 @@ export const getAvailableDistrictrMaps: ( offset?: number ) => Promise = async (limit = 10, offset = 0) => { return await axios - .get( - `${process.env.NEXT_PUBLIC_API_URL}/api/gerrydb/views?limit=${limit}&offset=${offset}` - ) - .then((res) => { + .get(`${process.env.NEXT_PUBLIC_API_URL}/api/gerrydb/views?limit=${limit}&offset=${offset}`) + .then(res => { return res.data; }); }; @@ -210,7 +201,7 @@ export const patchUpdateAssignments: ( .patch(`${process.env.NEXT_PUBLIC_API_URL}/api/update_assignments`, { assignments: assignments, }) - .then((res) => { + .then(res => { return res.data; }); }; @@ -222,7 +213,7 @@ export const patchUpdateAssignments: ( * @property {Assignment[]} children - The children. */ export interface ShatterResult { - parents: { geoids: string[] }; + parents: {geoids: string[]}; children: Assignment[]; } @@ -236,7 +227,7 @@ export interface ShatterResult { export const patchShatterParents: (params: { document_id: string; geoids: string[]; -}) => Promise = async ({ document_id, geoids }) => { +}) => Promise = async ({document_id, geoids}) => { return await axios .patch( `${process.env.NEXT_PUBLIC_API_URL}/api/update_assignments/${document_id}/shatter_parents`, @@ -244,7 +235,7 @@ export const patchShatterParents: (params: { geoids: geoids, } ) - .then((res) => { + .then(res => { return res.data; }); }; diff --git a/app/src/app/utils/api/mutations.ts b/app/src/app/utils/api/mutations.ts index be1e7df90..6bdc1d580 100644 --- a/app/src/app/utils/api/mutations.ts +++ b/app/src/app/utils/api/mutations.ts @@ -1,18 +1,18 @@ -import { MutationObserver } from "@tanstack/query-core"; -import { queryClient } from "./queryClient"; +import {MutationObserver} from '@tanstack/query-core'; +import {queryClient} from './queryClient'; import { AssignmentsCreate, createMapDocument, patchShatterParents, patchUpdateAssignments, -} from "@/app/utils/api/apiHandlers"; -import { useMapStore } from "@/app/store/mapStore"; -import { mapMetrics } from "./queries"; -import { use } from "react"; +} from '@/app/utils/api/apiHandlers'; +import {useMapStore} from '@/app/store/mapStore'; +import {mapMetrics} from './queries'; +import {use} from 'react'; export const patchShatter = new MutationObserver(queryClient, { mutationFn: patchShatterParents, - onMutate: ({ document_id, geoids }) => { + onMutate: ({document_id, geoids}) => { useMapStore.getState().setMapLock(true); console.log( `Shattering parents for ${geoids} in document ${document_id}...`, @@ -20,13 +20,11 @@ export const patchShatter = new MutationObserver(queryClient, { performance.now() ); }, - onError: (error) => { - console.log("Error updating assignments: ", error); + onError: error => { + console.log('Error updating assignments: ', error); }, - onSuccess: (data) => { - console.log( - `Successfully shattered parents into ${data.children.length} children` - ); + onSuccess: data => { + console.log(`Successfully shattered parents into ${data.children.length} children`); return data; }, }); @@ -34,15 +32,13 @@ export const patchShatter = new MutationObserver(queryClient, { export const patchUpdates = new MutationObserver(queryClient, { mutationFn: patchUpdateAssignments, onMutate: () => { - console.log("Updating assignments"); + console.log('Updating assignments'); }, - onError: (error) => { - console.log("Error updating assignments: ", error); + onError: error => { + console.log('Error updating assignments: ', error); }, onSuccess: (data: AssignmentsCreate) => { - console.log( - `Successfully upserted ${data.assignments_upserted} assignments` - ); + console.log(`Successfully upserted ${data.assignments_upserted} assignments`); mapMetrics.refetch(); }, }); @@ -50,18 +46,18 @@ export const patchUpdates = new MutationObserver(queryClient, { export const document = new MutationObserver(queryClient, { mutationFn: createMapDocument, onMutate: () => { - console.log("Creating document"); - useMapStore.getState().setAppLoadingState("loading"); + console.log('Creating document'); + useMapStore.getState().setAppLoadingState('loading'); useMapStore.getState().resetZoneAssignments(); }, - onError: (error) => { - console.error("Error creating map document: ", error); + onError: error => { + console.error('Error creating map document: ', error); }, - onSuccess: (data) => { + onSuccess: data => { useMapStore.getState().setMapDocument(data); - useMapStore.getState().setAppLoadingState("loaded"); + useMapStore.getState().setAppLoadingState('loaded'); const documentUrl = new URL(window.location.toString()); - documentUrl.searchParams.set("document_id", data.document_id); - history.pushState({}, "", documentUrl.toString()); + documentUrl.searchParams.set('document_id', data.document_id); + history.pushState({}, '', documentUrl.toString()); }, }); diff --git a/app/src/app/utils/api/queries.ts b/app/src/app/utils/api/queries.ts index b4f3cd552..e50f7996c 100644 --- a/app/src/app/utils/api/queries.ts +++ b/app/src/app/utils/api/queries.ts @@ -1,5 +1,5 @@ -import { QueryObserver, skipToken } from "@tanstack/react-query"; -import { queryClient } from "./queryClient"; +import {QueryObserver, skipToken} from '@tanstack/react-query'; +import {queryClient} from './queryClient'; import { DistrictrMap, getAvailableDistrictrMaps, @@ -9,48 +9,47 @@ import { getDocument, getZonePopulations, ZonePopulation, -} from "./apiHandlers"; -import { MapStore, useMapStore } from "@/app/store/mapStore"; +} from './apiHandlers'; +import {MapStore, useMapStore} from '@/app/store/mapStore'; -const INITIAL_VIEW_LIMIT = 30 -const INITIAL_VIEW_OFFSET = 0 +const INITIAL_VIEW_LIMIT = 30; +const INITIAL_VIEW_OFFSET = 0; export const mapMetrics = new QueryObserver(queryClient, { - queryKey: ["_zonePopulations"], + queryKey: ['_zonePopulations'], queryFn: skipToken, }); export const updateMapMetrics = (mapDocument: DocumentObject) => { mapMetrics.setOptions({ - queryKey: ["zonePopulations", mapDocument.document_id], + queryKey: ['zonePopulations', mapDocument.document_id], queryFn: mapDocument ? () => getZonePopulations(mapDocument) : skipToken, }); }; - -mapMetrics.subscribe((result) => { +mapMetrics.subscribe(result => { useMapStore.getState().setMapMetrics(result); }); export const mapViewsQuery = new QueryObserver(queryClient, { - queryKey: ["views", INITIAL_VIEW_LIMIT, INITIAL_VIEW_OFFSET], + queryKey: ['views', INITIAL_VIEW_LIMIT, INITIAL_VIEW_OFFSET], queryFn: () => getAvailableDistrictrMaps(INITIAL_VIEW_LIMIT, INITIAL_VIEW_OFFSET), }); export const updateMapViews = (limit: number, offset: number) => { mapViewsQuery.setOptions({ - queryKey: ["views", limit, offset], + queryKey: ['views', limit, offset], queryFn: () => getAvailableDistrictrMaps(limit, offset), }); }; export const getMapViewsSubs = (_useMapStore: typeof useMapStore) => { - mapViewsQuery.subscribe((result) => { + mapViewsQuery.subscribe(result => { if (result) { - _useMapStore.getState().setMapViews(result) + _useMapStore.getState().setMapViews(result); } - }) -} + }); +}; const getDocumentFunction = (documentId?: string) => { return async () => { @@ -61,53 +60,46 @@ const getDocumentFunction = (documentId?: string) => { } else { return null; } -} -} + }; +}; -export const updateDocumentFromId = new QueryObserver( - queryClient, - { - queryKey: ["mapDocument", undefined], - queryFn: getDocumentFunction() - }, -); +export const updateDocumentFromId = new QueryObserver(queryClient, { + queryKey: ['mapDocument', undefined], + queryFn: getDocumentFunction(), +}); -export const updateGetDocumentFromId = (documentId:string) => { +export const updateGetDocumentFromId = (documentId: string) => { updateDocumentFromId.setOptions({ - queryKey: ["mapDocument", documentId], - queryFn: getDocumentFunction(documentId) + queryKey: ['mapDocument', documentId], + queryFn: getDocumentFunction(documentId), }); -} +}; -updateDocumentFromId.subscribe((mapDocument) => { +updateDocumentFromId.subscribe(mapDocument => { if (mapDocument.data) { useMapStore.getState().setMapDocument(mapDocument.data); } }); const getFetchAssignmentsQuery = (mapDocument?: MapStore['mapDocument']) => { - if (!mapDocument) return () => null - return async () => await getAssignments(mapDocument) -} + if (!mapDocument) return () => null; + return async () => await getAssignments(mapDocument); +}; -export const fetchAssignments = new QueryObserver( - queryClient, - { - queryKey: ["assignments"], - queryFn: getFetchAssignmentsQuery(), - } -) +export const fetchAssignments = new QueryObserver(queryClient, { + queryKey: ['assignments'], + queryFn: getFetchAssignmentsQuery(), +}); export const updateAssignments = (mapDocument: DocumentObject) => { fetchAssignments.setOptions({ queryFn: getFetchAssignmentsQuery(mapDocument), - queryKey: ['assignments', performance.now()] - }) -} - + queryKey: ['assignments', performance.now()], + }); +}; -fetchAssignments.subscribe((assignments) => { +fetchAssignments.subscribe(assignments => { if (assignments.data) { useMapStore.getState().loadZoneAssignments(assignments.data); } -}); \ No newline at end of file +}); diff --git a/app/src/app/utils/api/queryClient.ts b/app/src/app/utils/api/queryClient.ts index 7b3125501..34adc3d71 100644 --- a/app/src/app/utils/api/queryClient.ts +++ b/app/src/app/utils/api/queryClient.ts @@ -1,2 +1,2 @@ -import { QueryClient } from "@tanstack/react-query"; -export const queryClient = new QueryClient(); \ No newline at end of file +import {QueryClient} from '@tanstack/react-query'; +export const queryClient = new QueryClient(); diff --git a/app/src/app/utils/api/queryParamsListener.ts b/app/src/app/utils/api/queryParamsListener.ts index 955ed7521..37fdb7364 100644 --- a/app/src/app/utils/api/queryParamsListener.ts +++ b/app/src/app/utils/api/queryParamsListener.ts @@ -1,10 +1,10 @@ -import { updateDocumentFromId, updateGetDocumentFromId } from "./queries"; -export let previousDocumentID = '' +import {updateDocumentFromId, updateGetDocumentFromId} from './queries'; +export let previousDocumentID = ''; export const getSearchParamsObersver = () => { // next ssr safety - if (typeof window === "undefined") { - return + if (typeof window === 'undefined') { + return; } // listener for tab refocus @@ -16,17 +16,15 @@ export const getSearchParamsObersver = () => { document.addEventListener('visibilitychange', handleVisibilityChange); - let previousDocumentID = ""; + let previousDocumentID = ''; const observer = new MutationObserver(() => { - const documentId = new URLSearchParams(window.location.search).get( - "document_id" - ); + const documentId = new URLSearchParams(window.location.search).get('document_id'); if (documentId && documentId !== previousDocumentID) { - previousDocumentID = documentId - updateGetDocumentFromId(documentId) + previousDocumentID = documentId; + updateGetDocumentFromId(documentId); } }); - const config = { subtree: true, childList: true }; + const config = {subtree: true, childList: true}; // start listening to changes observer.observe(document, config); return observer; diff --git a/app/src/app/utils/arrays.ts b/app/src/app/utils/arrays.ts index e6990774a..bd44fcba2 100644 --- a/app/src/app/utils/arrays.ts +++ b/app/src/app/utils/arrays.ts @@ -1,3 +1,3 @@ export const onlyUnique = (value: unknown, index: number, self: unknown[]) => { - return self.indexOf(value) === index; + return self.indexOf(value) === index; }; diff --git a/app/src/app/utils/events/handlers.ts b/app/src/app/utils/events/handlers.ts index 18c29e4c1..157469ba3 100644 --- a/app/src/app/utils/events/handlers.ts +++ b/app/src/app/utils/events/handlers.ts @@ -1,9 +1,9 @@ -import { BLOCK_SOURCE_ID } from "@/app/constants/layers"; -import { MutableRefObject } from "react"; -import { Map, MapGeoJSONFeature } from "maplibre-gl"; -import { debounce } from "lodash"; -import { NullableZone, Zone } from "@/app/constants/types"; -import { MapStore } from "@/app/store/mapStore"; +import {BLOCK_SOURCE_ID} from '@/app/constants/layers'; +import {MutableRefObject} from 'react'; +import {Map, MapGeoJSONFeature} from 'maplibre-gl'; +import {debounce} from 'lodash'; +import {NullableZone, Zone} from '@/app/constants/types'; +import {MapStore} from '@/app/store/mapStore'; /** * Debounced function to set zone assignments in the store without resetting the state every time the mouse moves (assuming onhover event). @@ -19,11 +19,11 @@ const debouncedSetZoneAssignments = debounce( const population = Array.from(Object.values(accumulatedBlockPopulations)).reduce( (acc, val) => acc + Number(val), - 0, + 0 ); selectedZone && mapStoreRef.setZonePopulations(selectedZone, population); }, - 1, // 1ms debounce + 1 // 1ms debounce ); /** @@ -40,32 +40,30 @@ const debouncedSetZoneAssignments = debounce( export const SelectMapFeatures = ( features: Array | undefined, map: Map | null, - mapStoreRef: MapStore, + mapStoreRef: MapStore ) => { if (map) { - let { accumulatedGeoids, accumulatedBlockPopulations, activeTool } = - mapStoreRef; - const selectedZone = - activeTool === "eraser" ? null : mapStoreRef.selectedZone; + let {accumulatedGeoids, accumulatedBlockPopulations, activeTool} = mapStoreRef; + const selectedZone = activeTool === 'eraser' ? null : mapStoreRef.selectedZone; - features?.forEach((feature) => { + features?.forEach(feature => { map.setFeatureState( { source: BLOCK_SOURCE_ID, id: feature?.id ?? undefined, sourceLayer: feature.sourceLayer, }, - { selected: true, zone: selectedZone } + {selected: true, zone: selectedZone} ); }); if (features?.length) { - features.forEach((feature) => { + features.forEach(feature => { accumulatedGeoids.add(feature.properties?.path); - accumulatedBlockPopulations.set(feature.properties?.path, feature.properties?.total_pop) + accumulatedBlockPopulations.set(feature.properties?.path, feature.properties?.total_pop); }); } } - return new Promise((resolve) => { + return new Promise(resolve => { // Resolve the Promise after the function completes // this is so we can chain the function and call the next one resolve(); @@ -84,8 +82,8 @@ export const SelectZoneAssignmentFeatures = (mapStoreRef: MapStore) => { if (accumulatedGeoids?.size) { debouncedSetZoneAssignments( mapStoreRef, - mapStoreRef.activeTool === "brush" ? mapStoreRef.selectedZone : null, - mapStoreRef.accumulatedGeoids, + mapStoreRef.activeTool === 'brush' ? mapStoreRef.selectedZone : null, + mapStoreRef.accumulatedGeoids ); } }; @@ -99,7 +97,7 @@ export const SelectZoneAssignmentFeatures = (mapStoreRef: MapStore) => { export const ResetMapSelectState = ( map: Map | null, mapStoreRef: MapStore, - sourceLayer: string, + sourceLayer: string ) => { if (map && Object.keys(mapStoreRef.zoneAssignments).length) { map.removeFeatureState({ @@ -107,7 +105,7 @@ export const ResetMapSelectState = ( sourceLayer: sourceLayer, }); - mapStoreRef.setAccumulatedGeoids(new Set()) + mapStoreRef.setAccumulatedGeoids(new Set()); // reset zoneAssignments mapStoreRef.resetZoneAssignments(); // confirm the map has been reset diff --git a/app/src/app/utils/helpers.ts b/app/src/app/utils/helpers.ts index 18db33049..8953242a4 100644 --- a/app/src/app/utils/helpers.ts +++ b/app/src/app/utils/helpers.ts @@ -6,13 +6,13 @@ import { MapGeoJSONFeature, LngLat, LngLatLike, -} from "maplibre-gl"; -import { Point } from "maplibre-gl"; -import { BLOCK_HOVER_LAYER_ID, BLOCK_SOURCE_ID } from "@/app/constants/layers"; -import { polygon, multiPolygon } from "@turf/helpers"; -import { booleanWithin } from "@turf/boolean-within"; -import { pointOnFeature } from "@turf/point-on-feature"; -import { MapStore, useMapStore } from "../store/mapStore"; +} from 'maplibre-gl'; +import {Point} from 'maplibre-gl'; +import {BLOCK_HOVER_LAYER_ID, BLOCK_SOURCE_ID} from '@/app/constants/layers'; +import {polygon, multiPolygon} from '@turf/helpers'; +import {booleanWithin} from '@turf/boolean-within'; +import {pointOnFeature} from '@turf/point-on-feature'; +import {MapStore, useMapStore} from '../store/mapStore'; /** * PaintEventHandler @@ -25,7 +25,7 @@ export type PaintEventHandler = ( map: Map | null, e: MapLayerMouseEvent | MapLayerTouchEvent, brushSize: number, - layers?: string[], + layers?: string[] ) => MapGeoJSONFeature[] | undefined; /** @@ -54,7 +54,7 @@ export type ContextMenuState = { */ export const boxAroundPoint = ( e: MapLayerMouseEvent | MapLayerTouchEvent, - radius: number, + radius: number ): [PointLike, PointLike] => { return [ [e.point.x - radius, e.point.y - radius], @@ -74,11 +74,11 @@ export const getFeaturesInBbox = ( map: Map | null, e: MapLayerMouseEvent | MapLayerTouchEvent, brushSize: number, - layers: string[] = [BLOCK_HOVER_LAYER_ID], + layers: string[] = [BLOCK_HOVER_LAYER_ID] ): MapGeoJSONFeature[] | undefined => { const bbox = boxAroundPoint(e, brushSize); - return map?.queryRenderedFeatures(bbox, { layers }); + return map?.queryRenderedFeatures(bbox, {layers}); }; /** @@ -93,9 +93,9 @@ export const getFeatureUnderCursor = ( map: Map | null, e: MapLayerMouseEvent | MapLayerTouchEvent, brushSize: number, - layers: string[] = [BLOCK_HOVER_LAYER_ID], + layers: string[] = [BLOCK_HOVER_LAYER_ID] ): MapGeoJSONFeature[] | undefined => { - return map?.queryRenderedFeatures(e.point, { layers }); + return map?.queryRenderedFeatures(e.point, {layers}); }; /** @@ -110,12 +110,12 @@ export const getFeaturesIntersectingCounties = ( map: Map | null, e: MapLayerMouseEvent | MapLayerTouchEvent, brushSize: number, - layers: string[] = [BLOCK_HOVER_LAYER_ID], + layers: string[] = [BLOCK_HOVER_LAYER_ID] ): MapGeoJSONFeature[] | undefined => { if (!map) return; const countyFeatures = map.queryRenderedFeatures(e.point, { - layers: ["counties_fill"], + layers: ['counties_fill'], }); if (!countyFeatures) return; @@ -139,7 +139,7 @@ export const getFeaturesIntersectingCounties = ( countyPoly = multiPolygon(countyFeatures[0].geometry.coordinates); } - return features.filter((p) => { + return features.filter(p => { const point = pointOnFeature(p); return booleanWithin(point, countyPoly); }); @@ -152,7 +152,7 @@ export const getFeaturesIntersectingCounties = ( * @returns [PointLike, PointLike] - An array containing the SW and NE corners of the bounding box */ const getBoundingBoxFromFeatures = ( - features: MapGeoJSONFeature[], + features: MapGeoJSONFeature[] ): [LngLatLike, LngLatLike] | null => { if (!features || features.length === 0) { return null; @@ -161,7 +161,7 @@ const getBoundingBoxFromFeatures = ( const sw = new LngLat(180, 90); const ne = new LngLat(-180, -90); - features.forEach((feature) => { + features.forEach(feature => { // this will always have an even number of coordinates // iterating over the coordinates in pairs yields (lng, lat) // @ts-ignore: Property 'coordinates' does not exist on type 'Geometry'. @@ -186,22 +186,19 @@ const getBoundingBoxFromFeatures = ( * @param e - MapLayerMouseEvent | MapLayerTouchEvent, the event object * @returns Point - The position of the mouse on the map */ -export const mousePos = ( - map: Map | null, - e: MapLayerMouseEvent | MapLayerTouchEvent, -) => { +export const mousePos = (map: Map | null, e: MapLayerMouseEvent | MapLayerTouchEvent) => { const canvas = map?.getCanvasContainer(); if (!canvas) return new Point(0, 0); const rect = canvas.getBoundingClientRect(); return new Point( e.point.x - rect.left - canvas.clientLeft, - e.point.y - rect.top - canvas.clientTop, + e.point.y - rect.top - canvas.clientTop ); }; export interface LayerVisibility { layerId: string; - visibility: "none" | "visible"; + visibility: 'none' | 'visible'; } /** @@ -218,18 +215,18 @@ export interface LayerVisibility { */ export function toggleLayerVisibility( mapRef: maplibregl.Map, - layerIds: string[], + layerIds: string[] ): LayerVisibility[] { - const activeLayerIds = getVisibleLayers(mapRef)?.map((layer) => layer.id); + const activeLayerIds = getVisibleLayers(mapRef)?.map(layer => layer.id); if (!activeLayerIds) return []; - return layerIds.map((layerId) => { + return layerIds.map(layerId => { if (activeLayerIds && activeLayerIds.includes(layerId)) { - mapRef.setLayoutProperty(layerId, "visibility", "none"); - return { layerId: layerId, visibility: "none" }; + mapRef.setLayoutProperty(layerId, 'visibility', 'none'); + return {layerId: layerId, visibility: 'none'}; } else { - mapRef.setLayoutProperty(layerId, "visibility", "visible"); - return { layerId: layerId, visibility: "visible" }; + mapRef.setLayoutProperty(layerId, 'visibility', 'visible'); + return {layerId: layerId, visibility: 'visible'}; } }, {}); } @@ -241,27 +238,23 @@ export function toggleLayerVisibility( * @param {maplibregl.Map} map - The map reference. */ export function getVisibleLayers(map: Map | null) { - return map?.getStyle().layers.filter((layer) => { - return layer.layout?.visibility === "visible"; + return map?.getStyle().layers.filter(layer => { + return layer.layout?.visibility === 'visible'; }); } export type ColorZoneAssignmentsState = [ - MapStore["zoneAssignments"], - MapStore["mapDocument"], - MapStore["getMapRef"], - MapStore["shatterIds"], - MapStore["appLoadingState"], - MapStore["mapRenderingState"], + MapStore['zoneAssignments'], + MapStore['mapDocument'], + MapStore['getMapRef'], + MapStore['shatterIds'], + MapStore['appLoadingState'], + MapStore['mapRenderingState'] ]; -export const getMap = (_getMapRef?: MapStore["getMapRef"]) => { +export const getMap = (_getMapRef?: MapStore['getMapRef']) => { const mapRef = _getMapRef?.() || useMapStore.getState().getMapRef(); - if ( - mapRef - ?.getStyle() - .layers.findIndex((layer) => layer.id === BLOCK_HOVER_LAYER_ID) !== -1 - ) { + if (mapRef?.getStyle().layers.findIndex(layer => layer.id === BLOCK_HOVER_LAYER_ID) !== -1) { return null; } @@ -289,44 +282,27 @@ export const getMap = (_getMapRef?: MapStore["getMapRef"]) => { */ export const colorZoneAssignments = ( state: ColorZoneAssignmentsState, - previousState?: ColorZoneAssignmentsState, + previousState?: ColorZoneAssignmentsState ) => { - const [ - zoneAssignments, - mapDocument, - getMapRef, - _, - appLoadingState, - mapRenderingState, - ] = state; + const [zoneAssignments, mapDocument, getMapRef, _, appLoadingState, mapRenderingState] = state; const previousZoneAssignments = previousState?.[0] || null; const mapRef = getMapRef(); const shatterIds = useMapStore.getState().shatterIds; - if ( - !mapRef || - !mapDocument || - appLoadingState !== "loaded" || - mapRenderingState !== "loaded" - ) { + if (!mapRef || !mapDocument || appLoadingState !== 'loaded' || mapRenderingState !== 'loaded') { return; } - const isInitialRender = - previousState?.[4] !== "loaded" || previousState?.[5] !== "loaded"; + const isInitialRender = previousState?.[4] !== 'loaded' || previousState?.[5] !== 'loaded'; zoneAssignments.forEach((zone, id) => { if ( - (id && - !isInitialRender && - previousZoneAssignments?.get(id) === zoneAssignments.get(id)) || + (id && !isInitialRender && previousZoneAssignments?.get(id) === zoneAssignments.get(id)) || !id ) { return; } const isChild = shatterIds.children.has(id); - const sourceLayer = isChild - ? mapDocument.child_layer - : mapDocument.parent_layer; + const sourceLayer = isChild ? mapDocument.child_layer : mapDocument.parent_layer; if (!sourceLayer) { return; @@ -341,17 +317,17 @@ export const colorZoneAssignments = ( { selected: true, zone, - }, + } ); }); }; // property changes on which to re-color assignments export const colorZoneAssignmentTriggers = [ - "zoneAssignments", - "mapDocument", - "mapRef", - "shatterIds", + 'zoneAssignments', + 'mapDocument', + 'mapRef', + 'shatterIds', ] as Array; /** @@ -368,13 +344,13 @@ export const colorZoneAssignmentTriggers = [ * This is typically used when "shattering" a parent element into its constituent parts. */ export const setZones = ( - zoneAssignments: MapStore["zoneAssignments"], + zoneAssignments: MapStore['zoneAssignments'], parent: string, - children: Set, + children: Set ) => { const zone = zoneAssignments.get(parent); if (zone) { - children.forEach((childId) => { + children.forEach(childId => { zoneAssignments.set(childId, zone); }); zoneAssignments.delete(parent);