From 8dd4b1e1bfb423c175840f5b29ca826697306dce Mon Sep 17 00:00:00 2001 From: Kichiyaki Date: Sun, 20 Dec 2020 19:31:04 +0100 Subject: [PATCH] add a new page - MapPage --- package.json | 2 + src/config/app.ts | 3 + src/features/ServerPage/ServerPage.tsx | 4 + .../ServerPage/features/MapPage/MapPage.tsx | 404 ++++++++++++++++++ .../features/MapPage/components/Map/Map.tsx | 82 ++++ .../components/MarkerField/MarkerField.tsx | 96 +++++ .../ServerPage/features/MapPage/queries.ts | 47 ++ .../ServerPage/features/MapPage/types.ts | 38 ++ .../ServerPage/features/MapPage/useMarkers.ts | 75 ++++ yarn.lock | 100 +++-- 10 files changed, 806 insertions(+), 45 deletions(-) create mode 100644 src/features/ServerPage/features/MapPage/MapPage.tsx create mode 100644 src/features/ServerPage/features/MapPage/components/Map/Map.tsx create mode 100644 src/features/ServerPage/features/MapPage/components/MarkerField/MarkerField.tsx create mode 100644 src/features/ServerPage/features/MapPage/queries.ts create mode 100644 src/features/ServerPage/features/MapPage/types.ts create mode 100644 src/features/ServerPage/features/MapPage/useMarkers.ts diff --git a/package.json b/package.json index 183ce54..638e9c4 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "typescript": "^4.0.3", "use-debounce": "^5.0.1", "use-query-params": "^1.1.8", + "uuid": "^8.3.2", "web-vitals": "^0.2.4" }, "scripts": { @@ -61,6 +62,7 @@ "devDependencies": { "@types/lodash": "^4.14.165", "@types/react-router-dom": "^5.1.6", + "@types/uuid": "^8.3.0", "babel-plugin-module-resolver": "^4.0.0", "babel-plugin-transform-imports": "^2.0.0", "customize-cra": "^1.0.0", diff --git a/src/config/app.ts b/src/config/app.ts index daefcd0..85b42f7 100644 --- a/src/config/app.ts +++ b/src/config/app.ts @@ -12,6 +12,9 @@ export const SERVER_STATUS = { export const TWHELP = process.env.REACT_APP_TWHELP ?? 'https://tribalwarshelp.com'; +export const MAP_SERVICE = + process.env.REACT_APP_MAP_SERVICE ?? 'https://api.tribalwarshelp.com/map'; + export const AUTHOR = 'Dawid WysokiƄski'; export const DATE_FORMAT = { diff --git a/src/features/ServerPage/ServerPage.tsx b/src/features/ServerPage/ServerPage.tsx index 309b46e..af8cf6d 100644 --- a/src/features/ServerPage/ServerPage.tsx +++ b/src/features/ServerPage/ServerPage.tsx @@ -8,6 +8,7 @@ import PlayerPage from './features/PlayerPage/PlayerPage'; import TribePage from './features/TribePage/TribePage'; import VillagePage from './features/VillagePage/VillagePage'; import RankingPage from './features/RankingPage/RankingPage'; +import MapPage from './features/MapPage/MapPage'; import NotFoundPage from '../NotFoundPage/NotFoundPage'; const EnhancedRoute = ({ children, ...rest }: RouteProps) => { @@ -36,6 +37,9 @@ function ServerPage() { + + + diff --git a/src/features/ServerPage/features/MapPage/MapPage.tsx b/src/features/ServerPage/features/MapPage/MapPage.tsx new file mode 100644 index 0000000..3e19ebd --- /dev/null +++ b/src/features/ServerPage/features/MapPage/MapPage.tsx @@ -0,0 +1,404 @@ +import React, { useState } from 'react'; +import { useApolloClient } from '@apollo/client'; +import { useDebouncedCallback } from 'use-debounce'; +import useServer from '../../libs/ServerContext/useServer'; +import useMarkers from './useMarkers'; +import { MAP_SERVICE } from '@config/app'; +import { PLAYERS, TRIBES } from './queries'; + +import { makeStyles } from '@material-ui/core/styles'; +import { + Typography, + Container, + Button, + Grid, + TextField, + Checkbox, + FormControlLabel, +} from '@material-ui/core'; +import ServerPageLayout from '@features/ServerPage/common/PageLayout/PageLayout'; +import Map from './components/Map/Map'; +import MarkerField from './components/MarkerField/MarkerField'; + +import { + PlayersQueryVariables, + TribesQueryVariables, +} from '@libs/graphql/types'; +import { + Tribe, + Player, + PlayerList, + TribeList, + Settings, + PlayerMarker, + TribeMarker, +} from './types'; + +function MapPage() { + const [settings, setSettings] = useState({ + showBarbarian: false, + largerMarkers: false, + markersOnly: false, + centerX: 500, + centerY: 500, + scale: 1, + showGrid: true, + showContinentNumbers: true, + backgroundColor: '#000000', + gridLineColor: '#ffffff', + continentNumberColor: '#ffffff', + }); + const { + markers: tribeMarkers, + createDeleteMarkerHandler: createDeleteTribeMarkerHandler, + createUpdateMarkerColorHandler: createUpdateTribeMarkerColorHandler, + createUpdateMarkerItemHandler: createUpdateTribeMarkerItemHandler, + handleAddMarker: handleAddTribeMarker, + } = useMarkers(); + const { + markers: playerMarkers, + createDeleteMarkerHandler: createDeletePlayerMarkerHandler, + createUpdateMarkerColorHandler: createUpdatePlayerMarkerColorHandler, + createUpdateMarkerItemHandler: createUpdatePlayerMarkerItemHandler, + handleAddMarker: handleAddPlayerMarker, + } = useMarkers(); + const [mapURL, setMapURL] = useState(''); + const { key } = useServer(); + const classes = useStyles(); + const client = useApolloClient(); + + const handleSettingsChange = ( + e: React.ChangeEvent + ) => { + setSettings({ + ...settings, + [e.target.name]: + e.target.type === 'checkbox' && 'checked' in e.target + ? e.target.checked + : e.target.value, + }); + }; + const debouncedHandleSettingsChange = useDebouncedCallback( + handleSettingsChange, + 500 + ); + + const callDebouncedHandleSettingsChange = ( + e: React.ChangeEvent + ) => { + e.persist(); + debouncedHandleSettingsChange.callback(e); + }; + + const searchPlayers = async (searchValue: string): Promise => { + try { + const { data } = await client.query({ + query: PLAYERS, + variables: { + limit: 10, + filter: { + exists: true, + nameIEQ: searchValue + '%', + }, + server: key, + offset: 0, + sort: ['points DESC'], + }, + fetchPolicy: 'network-only', + }); + return data.players?.items ?? []; + } catch (error) { + return []; + } + }; + + const searchTribes = async (searchValue: string): Promise => { + try { + const { data } = await client.query({ + query: TRIBES, + variables: { + limit: 10, + filter: { + exists: true, + tagIEQ: searchValue + '%', + }, + server: key, + offset: 0, + sort: ['points DESC'], + }, + fetchPolicy: 'network-only', + }); + return data.tribes?.items ?? []; + } catch (error) { + return []; + } + }; + + const encodeMarker = (marker: PlayerMarker | TribeMarker): string => { + return encodeURIComponent(marker.item?.id + ',' + marker.color); + }; + + const handleSubmit = (e: React.FormEvent<{}>) => { + e.preventDefault(); + + let searchParams = ''; + Object.entries(settings).forEach( + ([key, value]: [string, string | number | boolean]) => { + searchParams += key + '=' + encodeURIComponent(value) + '&'; + } + ); + playerMarkers.forEach(marker => { + if (!marker.item) return; + searchParams += 'player=' + encodeMarker(marker) + '&'; + }); + tribeMarkers.forEach(marker => { + if (!marker.item) return; + searchParams += 'tribe=' + encodeMarker(marker) + '&'; + }); + + setMapURL(MAP_SERVICE + '/' + key + '?' + searchParams); + }; + + const tribeGetOptionLabel = (tribe: Tribe) => (tribe ? tribe.tag : ''); + const tribeGetOptionSelected = (option: Tribe, value: Tribe) => + option && value ? option.tag === value.tag : false; + const playerGetOptionLabel = (player: Player) => (player ? player.name : ''); + const playerGetOptionSelected = (option: Player, value: Player) => + option && value ? option.name === value.name : false; + + return ( + + +
+ + + + Settings + +
+ + + + + + + + } + /> + + } + /> + + } + /> + + } + /> + + } + /> +
+
+ + + Tribe markers + +
+ {tribeMarkers.map(marker => { + return ( + + ); + })} + +
+
+ + + Player markers + +
+ {playerMarkers.map(marker => { + return ( + + ); + })} + +
+
+ + + + + +
+
+ {mapURL && } +
+
+ ); +} + +const useStyles = makeStyles(theme => ({ + formGroup: { + '& > *': { + marginBottom: theme.spacing(1), + }, + }, +})); + +export default MapPage; diff --git a/src/features/ServerPage/features/MapPage/components/Map/Map.tsx b/src/features/ServerPage/features/MapPage/components/Map/Map.tsx new file mode 100644 index 0000000..248f098 --- /dev/null +++ b/src/features/ServerPage/features/MapPage/components/Map/Map.tsx @@ -0,0 +1,82 @@ +import React, { memo, useState, useEffect } from 'react'; + +import { makeStyles } from '@material-ui/core/styles'; +import { Link } from '@material-ui/core'; +import { Alert } from '@material-ui/lab'; +import Spinner from '@common/Spinner/Spinner'; + +export interface Props { + src: string; + alt: string; + maxWidth?: number; +} + +function Map({ src = '', alt = 'Map', maxWidth = 1000 }: Props) { + const [loading, setLoading] = useState(true); + const classes = useStyles(); + + useEffect(() => { + setLoading(true); + }, [src]); + + return ( +
+ {loading ? ( + It may take a while to generate a map! + ) : ( + + URL:{' '} + + {src} + + + )} +
+ {loading && ( + + )} + {alt} setLoading(false)} + className={classes.img} + /> +
+
+ ); +} + +const useStyles = makeStyles(theme => { + return { + img: { + display: 'block', + width: '100%', + height: 'auto', + }, + link: { + wordBreak: 'break-all', + }, + container: { + marginTop: theme.spacing(2), + }, + imageWrapper: { + marginTop: theme.spacing(1), + margin: 'auto', + }, + }; +}); + +export default memo(Map); diff --git a/src/features/ServerPage/features/MapPage/components/MarkerField/MarkerField.tsx b/src/features/ServerPage/features/MapPage/components/MarkerField/MarkerField.tsx new file mode 100644 index 0000000..2f18364 --- /dev/null +++ b/src/features/ServerPage/features/MapPage/components/MarkerField/MarkerField.tsx @@ -0,0 +1,96 @@ +import React, { useState } from 'react'; +import { useDebouncedCallback } from 'use-debounce'; +import useUpdateEffect from '@libs/useUpdateEffect'; + +import { TextField, Box, IconButton } from '@material-ui/core'; +import { Autocomplete } from '@material-ui/lab'; +import { Delete as DeleteIcon } from '@material-ui/icons'; + +export interface Props { + onDelete: () => void; + onChange: (e: React.ChangeEvent<{}>, value: T | null) => void; + onChangeColor: ( + e: React.ChangeEvent + ) => void; + getOptionLabel: (opt: T) => string; + getOptionSelected: (opt: T, value: T) => boolean; + loadSuggestions: (value: string) => Promise; +} + +function MarkerField({ + onDelete, + onChange, + loadSuggestions, + onChangeColor, + getOptionSelected, + getOptionLabel, +}: Props) { + const [searchValue, setSearchValue] = useState(''); + const [suggestions, setSuggestions] = useState([]); + const [loading, setLoading] = useState(true); + const debouncedOnChangeColor = useDebouncedCallback( + (e: React.ChangeEvent) => + onChangeColor(e), + 500 + ); + const debouncedLoadSuggestions = useDebouncedCallback( + (searchValue: string) => { + setLoading(true); + loadSuggestions(searchValue) + .then(data => { + setSuggestions(data); + }) + .finally(() => setLoading(false)); + }, + 1000 + ); + useUpdateEffect(() => { + debouncedLoadSuggestions.callback(searchValue); + }, [searchValue, debouncedLoadSuggestions]); + + return ( + + { + return ( + + + + ), + }} + type="text" + name="value" + onChange={e => setSearchValue(e.target.value)} + /> + ); + }} + /> + { + e.persist(); + debouncedOnChangeColor.callback(e); + }} + /> + + ); +} + +export default MarkerField; diff --git a/src/features/ServerPage/features/MapPage/queries.ts b/src/features/ServerPage/features/MapPage/queries.ts new file mode 100644 index 0000000..13086e7 --- /dev/null +++ b/src/features/ServerPage/features/MapPage/queries.ts @@ -0,0 +1,47 @@ +import { gql } from '@apollo/client'; + +export const PLAYERS = gql` + query players( + $server: String! + $filter: PlayerFilter! + $limit: Int! + $offset: Int! + $sort: [String!] + ) { + players( + server: $server + filter: $filter + limit: $limit + offset: $offset + sort: $sort + ) { + items { + id + name + } + } + } +`; + +export const TRIBES = gql` + query tribes( + $server: String! + $filter: TribeFilter! + $limit: Int! + $offset: Int! + $sort: [String!] + ) { + tribes( + server: $server + filter: $filter + limit: $limit + offset: $offset + sort: $sort + ) { + items { + id + tag + } + } + } +`; diff --git a/src/features/ServerPage/features/MapPage/types.ts b/src/features/ServerPage/features/MapPage/types.ts new file mode 100644 index 0000000..f97e215 --- /dev/null +++ b/src/features/ServerPage/features/MapPage/types.ts @@ -0,0 +1,38 @@ +import { List } from '@libs/graphql/types'; + +export type Tribe = { + id: number; + tag: string; +}; +export type TribeList = { + tribes?: List; +}; +export type Player = { + id: number; + name: string; +}; +export type PlayerList = { + players?: List; +}; + +export type Marker = { + id: string; + item?: T | null; + color: string; +}; +export type PlayerMarker = Marker; +export type TribeMarker = Marker; + +export type Settings = Object & { + showBarbarian: boolean; + largerMarkers: boolean; + markersOnly: boolean; + centerX: number; + centerY: number; + scale: number; + showGrid: boolean; + showContinentNumbers: boolean; + backgroundColor: string; + gridLineColor: string; + continentNumberColor: string; +}; diff --git a/src/features/ServerPage/features/MapPage/useMarkers.ts b/src/features/ServerPage/features/MapPage/useMarkers.ts new file mode 100644 index 0000000..85c5af6 --- /dev/null +++ b/src/features/ServerPage/features/MapPage/useMarkers.ts @@ -0,0 +1,75 @@ +import { useState } from 'react'; +import { v4 as uuidv4 } from 'uuid'; +import { Marker } from './types'; + +export type MarkerBag = { + markers: Marker[]; + handleAddMarker: () => void; + createUpdateMarkerItemHandler: ( + id: string + ) => (e: React.ChangeEvent<{}>, value: T | null) => void; + createUpdateMarkerColorHandler: ( + id: string + ) => (e: React.ChangeEvent) => void; + createDeleteMarkerHandler: (id: string) => () => void; +}; + +const useMarkers = (): MarkerBag => { + const [markers, setMarkers] = useState[]>([]); + + const getNewMarker = (): Marker => ({ + id: uuidv4(), + item: undefined, + color: '#000000', + }); + + const handleAddMarker = () => { + setMarkers([...markers, getNewMarker()]); + }; + + const createDeleteMarkerHandler = (id: string) => () => { + setMarkers(markers.filter(marker => marker.id !== id)); + }; + + const createUpdateMarkerItemHandler = (id: string) => ( + e: React.ChangeEvent<{}>, + item: T | null + ): void => { + setMarkers( + markers.map(marker => { + if (marker.id !== id) return marker; + if (item || item === null) { + return { + ...marker, + item, + }; + } + return marker; + }) + ); + }; + + const createUpdateMarkerColorHandler = (id: string) => ( + e: React.ChangeEvent + ): void => { + setMarkers( + markers.map(marker => { + if (marker.id !== id) return marker; + return { + ...marker, + color: e.target.value, + }; + }) + ); + }; + + return { + markers, + handleAddMarker, + createUpdateMarkerItemHandler, + createUpdateMarkerColorHandler, + createDeleteMarkerHandler, + }; +}; + +export default useMarkers; diff --git a/yarn.lock b/yarn.lock index 426c4e3..075c142 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1384,30 +1384,30 @@ prop-types "^15.7.2" react-is "^16.8.0 || ^17.0.0" -"@nivo/annotations@0.65.1": - version "0.65.1" - resolved "https://registry.yarnpkg.com/@nivo/annotations/-/annotations-0.65.1.tgz#d9bdf6b66b636183191109446759c06cc2e778b2" - integrity sha512-JNViguRGDm8vt6N5JhV/ugPsnesFuL826CWUnPfqkHj06eLn4fnsnGKBnOqxXwNSrV4GbJJBBfrzWOpz3drW/g== +"@nivo/annotations@0.67.0": + version "0.67.0" + resolved "https://registry.yarnpkg.com/@nivo/annotations/-/annotations-0.67.0.tgz#81f309d4427295a8afe847989480c4f3a71137d8" + integrity sha512-Qfracwd9we2nWBaNOAp0Lnt9uc86yRFDcQI3jsOdjFdzDA4lRwhkD85Lq477w1XrU7mtpjeRGsaKTCJtaorWEg== dependencies: - "@nivo/colors" "0.65.1" + "@nivo/colors" "0.67.0" lodash "^4.17.11" react-spring "9.0.0-rc.3" -"@nivo/axes@0.65.1": - version "0.65.1" - resolved "https://registry.yarnpkg.com/@nivo/axes/-/axes-0.65.1.tgz#ea9576fe9d7b9ac84430cc91e0b30af3ee9bba76" - integrity sha512-H2/8wM9xwn/F0GH47IgLmPaw6TuLqRIIojfPvQNM1gWgJYaBsghPxGfrXF2f8URjwRpihptbrlDVmg3OwRykVQ== +"@nivo/axes@0.67.0": + version "0.67.0" + resolved "https://registry.yarnpkg.com/@nivo/axes/-/axes-0.67.0.tgz#5892a8c90f782e478015865f779b62f2e74b7665" + integrity sha512-csqEgFoJQGoB5/TDSy7SXCy/2QSdrfSa51AMU/RhzpnZ35wNO/zHkEfP+ApvB8nuuwVuBNOShio80PNZOOD+Og== dependencies: - "@nivo/scales" "0.65.0" + "@nivo/scales" "0.67.0" d3-format "^1.4.4" d3-time "^1.0.11" d3-time-format "^2.1.3" react-spring "9.0.0-rc.3" -"@nivo/colors@0.65.1": - version "0.65.1" - resolved "https://registry.yarnpkg.com/@nivo/colors/-/colors-0.65.1.tgz#d55ec085c991358d88e3bce7c94be468e58b3817" - integrity sha512-1dU6fuHYUDbU2oqOA8jzlYI9qXOajgbwH2cs8s9XktHvC3rfxp6ZedqAI+FxqKuk9QFaAxcyFftYUVlpdsFFkQ== +"@nivo/colors@0.67.0": + version "0.67.0" + resolved "https://registry.yarnpkg.com/@nivo/colors/-/colors-0.67.0.tgz#5a2adc4b55406466efb8bbafecc08249e4e94e69" + integrity sha512-y8x76SzQ4HYm6kkWYfBGQSE5fy/jtqGhCBjivlKsouU9Hv2G8g4a2JVMsfadJQHQIUjIsM/7Q0Y7zasFM9wkgA== dependencies: d3-color "^2.0.0" d3-scale "^3.0.0" @@ -1415,10 +1415,10 @@ lodash "^4.17.11" react-motion "^0.5.2" -"@nivo/core@^0.65.0": - version "0.65.0" - resolved "https://registry.yarnpkg.com/@nivo/core/-/core-0.65.0.tgz#a356dcd740d7f70027edece36828185741fc3ff9" - integrity sha512-9ag4Stx0aWkiIFArg6X+eTDzZEBJyx08UhIfxvUcMnkda8OcYlAPrnp2K7sV5d7egIrnsxBpDt2lx/cC7XL/pg== +"@nivo/core@^0.67.0": + version "0.67.0" + resolved "https://registry.yarnpkg.com/@nivo/core/-/core-0.67.0.tgz#29f07b8bed2bcefb9402d14a9abe2895c5b2bfa2" + integrity sha512-F8amsf/MnIuZLoN6ikla8bKlUkUI3HVhy6R2qMF2jDS5xnYch3Sno9OPTTuR8RnYGCr57yClnvFuJzw251GE6g== dependencies: d3-color "^2.0.0" d3-format "^1.4.4" @@ -1433,49 +1433,49 @@ recompose "^0.30.0" resize-observer-polyfill "^1.5.1" -"@nivo/legends@0.65.1": - version "0.65.1" - resolved "https://registry.yarnpkg.com/@nivo/legends/-/legends-0.65.1.tgz#6a49329a8a7939d889345da95974d8520c2d4ede" - integrity sha512-ulJmhu9ZO5b5qp5YhMbEZ6+2PZfahd9jkXECSizwKyZ49FsTptiyLx8H4NTkmk2fmonhRt/W6IxEaUNG0/12Lg== +"@nivo/legends@0.67.0": + version "0.67.0" + resolved "https://registry.yarnpkg.com/@nivo/legends/-/legends-0.67.0.tgz#9cbe99d8929c6addafd8253f65b7e040d9d4bb6c" + integrity sha512-W6JWMSiiAPsDhuofwq7x3ERA2fFJ2J/aj+Y3lvrZh5OAsG6/PCljwhlhMklNgYoN6bT/+Jgtut3Agdl0Dlzspg== dependencies: lodash "^4.17.11" recompose "^0.30.0" -"@nivo/line@^0.65.1": - version "0.65.1" - resolved "https://registry.yarnpkg.com/@nivo/line/-/line-0.65.1.tgz#9efced4734d6d16a89a1423069f81eb58a2b6103" - integrity sha512-dcw3fxQeFE6NHLexYLKipvlOSG7/gUoHTt8mpcrjxQfThR3ugAjPW6O/1frVcrKYzouLxDTWpl9C7uWupgtzaQ== +"@nivo/line@^0.67.0": + version "0.67.0" + resolved "https://registry.yarnpkg.com/@nivo/line/-/line-0.67.0.tgz#c9abde9e1ac4f758377775e1d266a40aedb5c1ea" + integrity sha512-+iZpvVekl6GXZl+GnqL5kvtIhNl05tkcCJ6ajheVmOuzaFV7J9xBk8E3bFqNtFDM+vt4b0ggujW8zrlrZvrwUg== dependencies: - "@nivo/annotations" "0.65.1" - "@nivo/axes" "0.65.1" - "@nivo/colors" "0.65.1" - "@nivo/legends" "0.65.1" - "@nivo/scales" "0.65.0" - "@nivo/tooltip" "0.65.1" - "@nivo/voronoi" "0.65.1" + "@nivo/annotations" "0.67.0" + "@nivo/axes" "0.67.0" + "@nivo/colors" "0.67.0" + "@nivo/legends" "0.67.0" + "@nivo/scales" "0.67.0" + "@nivo/tooltip" "0.67.0" + "@nivo/voronoi" "0.67.0" d3-shape "^1.3.5" react-spring "9.0.0-rc.3" -"@nivo/scales@0.65.0": - version "0.65.0" - resolved "https://registry.yarnpkg.com/@nivo/scales/-/scales-0.65.0.tgz#60eb790680b49d06396c403c08cfbef68fb7e82f" - integrity sha512-0mRyvPJg3LGKkXraH8sQPvDVnLk2kmRNVjJKPRXWZ9ezMJUTfQb802p74/t/lo/AtAyscN7/sIfMsJ5ZJW4jkQ== +"@nivo/scales@0.67.0": + version "0.67.0" + resolved "https://registry.yarnpkg.com/@nivo/scales/-/scales-0.67.0.tgz#8e79e990ebd555bdce7c3dcdd73b8ad46cb0a74a" + integrity sha512-hXDeh3GzjZA3CcvJp14vCp0/QeoYMxVC2dZl55rIJdW200M+ET/ZtJQA2W1mDOGQUxR9z1flFvGJA+EqXhThwQ== dependencies: d3-scale "^3.0.0" d3-time-format "^2.1.3" lodash "^4.17.11" -"@nivo/tooltip@0.65.1": - version "0.65.1" - resolved "https://registry.yarnpkg.com/@nivo/tooltip/-/tooltip-0.65.1.tgz#7b3215e54dbfbaa2b4066b764f74c85137a8a576" - integrity sha512-m08E1ZSoSUS7O8Bi/6ewXM87w+t09ESNobFL6YTRro1vhnBZ2g8MlglIkXBkEP/mYqfyUMzw6DzT/tOaA3Cnlg== +"@nivo/tooltip@0.67.0": + version "0.67.0" + resolved "https://registry.yarnpkg.com/@nivo/tooltip/-/tooltip-0.67.0.tgz#c849ab7a3ee82d88ff6376894a2de5ef266c8e8d" + integrity sha512-Z4h4Ks/fFd7Cl2uSG/trfSYLXaiQNyFX2wGJrE/UPzDSpf4XqaW8uEBaK3p46200WG2AgltG0fHrouGNyMJ+1g== dependencies: react-spring "9.0.0-rc.3" -"@nivo/voronoi@0.65.1": - version "0.65.1" - resolved "https://registry.yarnpkg.com/@nivo/voronoi/-/voronoi-0.65.1.tgz#6a3ff0bb4d60ce78e96cfe3052fde622743e3ec5" - integrity sha512-9WUbLS4f9TQ3v3k8fhzKT9U0LOqKtGH4QcYhMNJxzJgsvb1wZavjPFd/CT+RsV7OD3zOWn/Nd7QEqeFLHwsJnA== +"@nivo/voronoi@0.67.0": + version "0.67.0" + resolved "https://registry.yarnpkg.com/@nivo/voronoi/-/voronoi-0.67.0.tgz#07ec873846ec12aa62d1c1884e274ea114b4341b" + integrity sha512-Z+e+fa92xWIhbpSRdQGJtei3bBHTbLnsmXtfje+Xz8LYpkyxp8R/iTs9cqzQ4KILp1Tv6EnQYWrFWNizN3fNGA== dependencies: d3-delaunay "^5.1.1" d3-scale "^3.0.0" @@ -2048,6 +2048,11 @@ dependencies: source-map "^0.6.1" +"@types/uuid@^8.3.0": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" + integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== + "@types/webpack-sources@*": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-2.0.0.tgz#08216ab9be2be2e1499beaebc4d469cec81e82a7" @@ -11849,6 +11854,11 @@ uuid@^8.3.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31" integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg== +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + v8-compile-cache@^2.0.3: version "2.1.1" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"