diff --git a/package.json b/package.json index 5987d5c..3aac53a 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "clsx": "^2.1.1", "conventional-changelog-conventionalcommits": "^7.0.2", "fuse.js": "^7.0.0", + "leaflet": "^1.9.4", "lucide-react": "^0.378.0", "next": "^14.2.1", "next-auth": "^4.24.6", @@ -45,6 +46,8 @@ "react-dom": "18.2.0", "react-hook-form": "^7.51.4", "react-icons": "^5.2.1", + "react-leaflet": "^4.2.1", + "redaxios": "^0.5.1", "semantic-release": "^23.1.1", "server-only": "^0.0.1", "sonner": "^1.4.41", @@ -55,6 +58,7 @@ }, "devDependencies": { "@types/eslint": "^8.56.2", + "@types/leaflet": "^1.9.12", "@types/node": "^20.11.20", "@types/nodemailer": "^6.4.15", "@types/react": "^18.2.57", @@ -63,6 +67,7 @@ "@typescript-eslint/parser": "^7.1.1", "eslint": "^8.57.0", "eslint-config-next": "^14.1.3", + "leaflet-defaulticon-compatibility": "^0.1.2", "postcss": "^8.4.34", "prettier": "^3.2.5", "prettier-plugin-tailwindcss": "^0.5.11", diff --git a/prisma/migrations/20240514165705_add_lat_long_to_shelter/migration.sql b/prisma/migrations/20240514165705_add_lat_long_to_shelter/migration.sql new file mode 100644 index 0000000..3dfe810 --- /dev/null +++ b/prisma/migrations/20240514165705_add_lat_long_to_shelter/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "Shelter" ADD COLUMN "latitude" DOUBLE PRECISION, +ADD COLUMN "longitude" DOUBLE PRECISION; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..fbffa92 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 4b79228..ccbd4af 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -39,6 +39,8 @@ model Shelter { addressNumber String addressNeighborhood String addressComplement String? + latitude Float? + longitude Float? } // Necessary for Next auth diff --git a/src/app/map/page.tsx b/src/app/map/page.tsx new file mode 100644 index 0000000..067848e --- /dev/null +++ b/src/app/map/page.tsx @@ -0,0 +1,45 @@ +"use client"; +import { type LatLngTuple } from "leaflet"; +import { Loader2 } from "lucide-react"; +import dynamic from "next/dynamic"; +import { useEffect, useState } from "react"; +import { api } from "~/trpc/react"; + +const DEFAULT_LOCATION: LatLngTuple = [-30.0346, -51.2177]; // Porto Alegre + +const MapComponent = dynamic(() => import("~/components/map/"), { + loading: () => , + ssr: false, +}); + +export default function Map() { + const { data, isLoading } = api.shelter.findAll.useQuery(); + const [userLocation, setUserLocation] = + useState(DEFAULT_LOCATION); + + useEffect(() => { + navigator.geolocation.getCurrentPosition( + (position) => { + const { latitude, longitude } = position.coords; + setUserLocation([latitude, longitude]); + }, + (error) => { + console.error("Error getting location: ", error); + }, + ); + }, []); + + if (isLoading && !data) { + return ( +
+ +
+ ); + } + + return ( +
+ +
+ ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index b99578b..470da67 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -53,7 +53,6 @@ export default function Home() {
- {/* */}
{!isLoading && !filteredShelters?.length && (
diff --git a/src/app/shelter/page.tsx b/src/app/shelter/page.tsx index 47d1034..37d3b06 100644 --- a/src/app/shelter/page.tsx +++ b/src/app/shelter/page.tsx @@ -1,5 +1,6 @@ "use client"; +import { useState } from "react"; import { useForm } from "react-hook-form"; import { Loader2 } from "lucide-react"; import { toast } from "sonner"; @@ -27,8 +28,11 @@ import { useShelterContext, } from "~/contexts/ShelterContext"; import { Card as CardBase, CardContent } from "~/components/ui/card"; +import { googleMaps } from "~/lib/google-maps"; function Shelter() { + const [isGettingCoordinates, setIsGettingCoordinates] = + useState(false); const { shelter } = useShelterContext(); const form = useForm>({ resolver: zodResolver(shelterSchema), @@ -60,15 +64,40 @@ function Shelter() { }, }); const isLoading = - createShelter.isPending || updateCurrentUserShelter.isPending; + createShelter.isPending || + updateCurrentUserShelter.isPending || + isGettingCoordinates; const isEditing = !!shelter; const hasModifiedInputs = Object.keys(form.formState.dirtyFields).length > 0; async function onSubmit(values: z.infer) { - if (isEditing) { - updateCurrentUserShelter.mutate(values); - } else { - createShelter.mutate(values); + try { + setIsGettingCoordinates(true); + const { street, number, city, state } = values.address; + const coordinates = await googleMaps.coordinates({ + street, + number, + city, + state, + }); + + const shelter = { + ...values, + address: { + ...values.address, + latitude: coordinates?.lat, + longitude: coordinates?.lng, + }, + }; + + const mutation = isEditing ? updateCurrentUserShelter : createShelter; + mutation.mutate(shelter); + } catch (error) { + toast.error( + "Ops! Houve um erro ao buscar as coordenadas do endereço e o abrigo não foi criado. Tente novamente!.", + ); + } finally { + setIsGettingCoordinates(false); } } diff --git a/src/components/card/index.tsx b/src/components/card/index.tsx index 7ec48e6..714e71f 100644 --- a/src/components/card/index.tsx +++ b/src/components/card/index.tsx @@ -13,15 +13,15 @@ import { unmaskPhone, unmaskSocialMedia } from "~/lib/masks"; type Props = { shelter: Shelter; -}; +} & React.ComponentProps; -export function Card({ shelter }: Props) { +export function Card({ shelter, ...otherProps }: Props) { const fullAddress = `${shelter.addressStreet} ${shelter.addressNumber} ${shelter.addressNeighborhood}, ${shelter.addressCity}, ${shelter.addressState}`; const availableVacancies = shelter.capacity - shelter.occupancy; return ( - +

{shelter.name}

{availableVacancies > 0 ? ( @@ -69,7 +69,7 @@ export function Card({ shelter }: Props) { )} - + ( @@ -28,6 +29,14 @@ export function Header() { Sobre +
  • + +
  • ); diff --git a/src/components/header/sidebar/index.tsx b/src/components/header/sidebar/index.tsx index 632ba10..017bf69 100644 --- a/src/components/header/sidebar/index.tsx +++ b/src/components/header/sidebar/index.tsx @@ -59,6 +59,13 @@ export function Sidebar() { +
  • + +
  • {!!session && ( <> diff --git a/src/components/map/index.tsx b/src/components/map/index.tsx new file mode 100644 index 0000000..505cfb1 --- /dev/null +++ b/src/components/map/index.tsx @@ -0,0 +1,59 @@ +import { useEffect } from "react"; +import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet"; +import "leaflet/dist/leaflet.css"; +import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css"; +import "leaflet-defaulticon-compatibility"; +import { type LatLngTuple } from "leaflet"; +import { type Shelter } from "@prisma/client"; +import { Card } from "../card"; + +function UserLocationMap({ userLocation }: { userLocation: LatLngTuple }) { + const map = useMap(); + + useEffect(() => { + if (userLocation) { + map.setView(userLocation, 13); + } + }, [userLocation, map]); + + return null; +} + +export default function Map({ + userLocation, + shelter, +}: { + userLocation: LatLngTuple; + shelter: Shelter[]; +}) { + return ( + + + + {shelter?.map((shelter) => { + if (!shelter.latitude || !shelter.longitude) return null; + + return ( + + + + + + ); + })} + + ); +} diff --git a/src/env.js b/src/env.js index 4ce7941..ad6a28f 100644 --- a/src/env.js +++ b/src/env.js @@ -38,6 +38,7 @@ export const env = createEnv({ */ client: { // NEXT_PUBLIC_CLIENTVAR: z.string(), + NEXT_PUBLIC_GOOGLE_MAPS_API_KEY: z.string(), }, /** @@ -51,6 +52,8 @@ export const env = createEnv({ NEXTAUTH_URL: process.env.NEXTAUTH_URL, GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET, + NEXT_PUBLIC_GOOGLE_MAPS_API_KEY: + process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY, EMAIL_HOST: process.env.EMAIL_HOST, EMAIL_PORT: process.env.EMAIL_PORT, EMAIL_USER: process.env.EMAIL_USER, diff --git a/src/lib/google-maps.ts b/src/lib/google-maps.ts new file mode 100644 index 0000000..1505692 --- /dev/null +++ b/src/lib/google-maps.ts @@ -0,0 +1,45 @@ +import axios from "redaxios"; +import { env } from "~/env"; + +type CoordinatesParams = { + street: string; + number: string; + city: string; + state: string; +}; + +type GeocodeResponse = { + results: Array<{ + geometry: { + location: { + lat: number; + lng: number; + }; + }; + }>; +}; + +const coordinates = async ({ + city, + number, + state, + street, +}: CoordinatesParams) => { + const response = await axios.get( + `https://maps.googleapis.com/maps/api/geocode/json`, + { + params: { + address: `${street} ${number}, ${city} - ${state}`, + key: env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY, + }, + }, + ); + + const { lat, lng } = response.data?.results?.[0]?.geometry.location ?? {}; + + return { lat, lng }; +}; + +export const googleMaps = { + coordinates, +}; diff --git a/src/schemas/shelter.ts b/src/schemas/shelter.ts index c8f9fc5..f43571b 100644 --- a/src/schemas/shelter.ts +++ b/src/schemas/shelter.ts @@ -57,3 +57,12 @@ export const shelterSchema = z.object({ }, "O nome de o usuário do Facebook deve começar com @"), }), }); + +export const apiShelterSchema = z.object({ + ...shelterSchema.shape, + address: z.object({ + ...shelterSchema.shape.address.shape, + latitude: z.number().optional(), + longitude: z.number().optional(), + }), +}); diff --git a/src/server/api/routers/shelter.ts b/src/server/api/routers/shelter.ts index 1056ef9..4f82e13 100644 --- a/src/server/api/routers/shelter.ts +++ b/src/server/api/routers/shelter.ts @@ -1,5 +1,5 @@ import { type z } from "zod"; -import { shelterSchema } from "~/schemas/shelter"; +import { apiShelterSchema } from "~/schemas/shelter"; import { createTRPCRouter, @@ -13,7 +13,7 @@ export const shelterRouter = createTRPCRouter({ return db.shelter.findMany(); }), findCurrentUserShelter: protectedProcedure.query( - async ({ ctx }): Promise | null> => { + async ({ ctx }): Promise | null> => { const result = await db.shelter.findFirst({ where: { createdById: ctx.session.user.id, @@ -41,12 +41,14 @@ export const shelterRouter = createTRPCRouter({ city: result.addressCity, complement: result.addressComplement ?? undefined, neighborhood: result.addressNeighborhood, + latitude: result.latitude ?? undefined, + longitude: result.longitude ?? undefined, }, }; }, ), create: protectedProcedure - .input(shelterSchema) + .input(apiShelterSchema) .mutation(async ({ ctx, input }) => { await db.shelter.create({ data: { @@ -66,11 +68,13 @@ export const shelterRouter = createTRPCRouter({ addressCity: input.address.city, addressComplement: input.address.complement, addressNeighborhood: input.address.neighborhood, + latitude: input.address.latitude, + longitude: input.address.longitude, }, }); }), updateCurrentUserShelter: protectedProcedure - .input(shelterSchema) + .input(apiShelterSchema) .mutation(async ({ input, ctx }) => { // This is currently only safe because we do not allow users to have more than one shelter on the FE. const result = await db.shelter.findFirst({ @@ -104,6 +108,8 @@ export const shelterRouter = createTRPCRouter({ addressCity: input.address.city, addressComplement: input.address.complement, addressNeighborhood: input.address.neighborhood, + latitude: input.address.latitude, + longitude: input.address.longitude, }, }); }), diff --git a/src/styles/globals.css b/src/styles/globals.css index c85cde9..9a2b0c2 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -5,3 +5,23 @@ html { scroll-behavior: smooth; } + +/* Reset leaflet style */ +.leaflet-container a { + color: inherit !important; +} + +.leaflet-popup-content { + margin: 0 !important; +} + +.leaflet-control { + z-index: 0 !important; +} +.leaflet-pane { + z-index: 0 !important; +} +.leaflet-top, +.leaflet-bottom { + z-index: 0 !important; +} diff --git a/yarn.lock b/yarn.lock index b78c083..648c985 100644 --- a/yarn.lock +++ b/yarn.lock @@ -110,9 +110,9 @@ "@floating-ui/utils" "^0.2.0" "@floating-ui/react-dom@^2.0.0": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.9.tgz#264ba8b061000baa132b5910f0427a6acf7ad7ce" - integrity sha512-q0umO0+LQK4+p6aGyvzASqKbKOJcAHJ7ycE9CuUvfx3s9zTHWmGJTPOIlM/hmSBfUfg/XfY5YhLBLR/LHwShQQ== + version "2.1.0" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.0.tgz#4f0e5e9920137874b2405f7d6c862873baf4beff" + integrity sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA== dependencies: "@floating-ui/dom" "^1.0.0" @@ -122,9 +122,9 @@ integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw== "@hookform/resolvers@^3.3.4": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-3.4.0.tgz#4ca2c08a26118fc8b6a572da94fdd57750a79b62" - integrity sha512-+oAqK3okmoEDnvUkJ3N/mvNMeeMv5Apgy1jkoRmlaaAF4vBgcJs9tHvtXU7VE4DvPosvAUUkPOaNFunzt1dbgA== + version "3.4.2" + resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-3.4.2.tgz#b69525248c2a9a1b2546411251ea25029915841a" + integrity sha512-1m9uAVIO8wVf7VCDAGsuGA0t6Z3m6jVGAN50HkV9vYLl0yixKK/Z1lr01vaRvYCkIKGoy1noVRxMzQYb4y/j1Q== "@humanwhocodes/config-array@^0.11.14": version "0.11.14" @@ -957,6 +957,11 @@ dependencies: "@babel/runtime" "^7.13.10" +"@react-leaflet/core@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@react-leaflet/core/-/core-2.1.0.tgz#383acd31259d7c9ae8fb1b02d5e18fe613c2a13d" + integrity sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg== + "@rushstack/eslint-patch@^1.3.3": version "1.10.3" resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.3.tgz#391d528054f758f81e53210f1a1eebcf1a8b1d20" @@ -1141,19 +1146,19 @@ "@tanstack/query-core" "5.36.1" "@trpc/client@next": - version "11.0.0-rc.373" - resolved "https://registry.yarnpkg.com/@trpc/client/-/client-11.0.0-rc.373.tgz#2bd00e5e9940d54e0b3a26786fb79200afc7c4dd" - integrity sha512-DSKOFjpQycJjwLrJWCpMqfwuFCP99QUPBZBeCb94WTvZUb6wGzOZWQMdIj7EnsR9jgWHlPll1e0s7OgAWxBKqw== + version "11.0.0-rc.374" + resolved "https://registry.yarnpkg.com/@trpc/client/-/client-11.0.0-rc.374.tgz#f33a5b449b2f7470bbba22036b2827ed0e318748" + integrity sha512-Ha1GaTT9FCq9BRPQPa+KKRTXSDRwvjHpsoYVl683vNoXnJRtTycMsPdydr/zdL10vuUHjutpLMZNycSRQ9yN0g== "@trpc/react-query@next": - version "11.0.0-rc.373" - resolved "https://registry.yarnpkg.com/@trpc/react-query/-/react-query-11.0.0-rc.373.tgz#67b8fe94eadf6b249c1a30b100641e56a6b13427" - integrity sha512-yxHlSiuPkoCnEB0W9yzF5eSX6F09/JFsTpdrwyocTg0Z1TaAYkJ0pUVMP1Gb3bKZEou1x6a8ZJJEqKLZbLPXCA== + version "11.0.0-rc.374" + resolved "https://registry.yarnpkg.com/@trpc/react-query/-/react-query-11.0.0-rc.374.tgz#53086f7e8fd205222987ad1b7ac647c922af38e5" + integrity sha512-zv/KjlxfeuOS5f0G2wl4L3AKzI/shYLj1sKxbtfGKkLRPMbCBqLlw4b37wRf5BLX4gi8f87FXm11Wwa8okD6aQ== "@trpc/server@next": - version "11.0.0-rc.373" - resolved "https://registry.yarnpkg.com/@trpc/server/-/server-11.0.0-rc.373.tgz#62cd41f0cda61a37c6616d26fe765de2a66ac648" - integrity sha512-i5q1KkQ0fuHqYbEPWMfk2rTp31wde8RKo0jxWfwZU8YsnjaErZ8lFnGCxz252l7mMCqT70IKR6c/N5MEXqChDA== + version "11.0.0-rc.374" + resolved "https://registry.yarnpkg.com/@trpc/server/-/server-11.0.0-rc.374.tgz#1d2fc943604cf5a1ca7407687bc33038ece8b751" + integrity sha512-7r76KJwbSV5mffEYQMGBIAVrrJdPot0JzYQD9ZvcInO8q9sn+uVVZQ8XCAq93zXDSodvzGBJhRu3Kn1qXPw5Xg== "@tufjs/canonical-json@2.0.0": version "2.0.0" @@ -1186,6 +1191,11 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/geojson@*": + version "7946.0.14" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.14.tgz#319b63ad6df705ee2a65a73ef042c8271e696613" + integrity sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg== + "@types/json-schema@*": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" @@ -1196,6 +1206,13 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/leaflet@^1.9.12": + version "1.9.12" + resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.9.12.tgz#a6626a0b3fba36fd34723d6e95b22e8024781ad6" + integrity sha512-BK7XS+NyRI291HIo0HCfE18Lp8oA30H1gpi1tf0mF3TgiCEzanQjOqNZ4x126SXzzi2oNSZhZ5axJp1k0iM6jg== + dependencies: + "@types/geojson" "*" + "@types/node@*", "@types/node@^20.11.20": version "20.12.12" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.12.tgz#7cbecdf902085cec634fdb362172dfe12b8f2050" @@ -1236,15 +1253,15 @@ csstype "^3.0.2" "@typescript-eslint/eslint-plugin@^7.1.1": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.9.0.tgz#093b96fc4e342226e65d5f18f9c87081e0b04a31" - integrity sha512-6e+X0X3sFe/G/54aC3jt0txuMTURqLyekmEHViqyA2VnxhLMpvA6nqmcjIy+Cr9tLDHPssA74BP5Mx9HQIxBEA== + version "7.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.10.0.tgz#07854a236f107bb45cbf4f62b89474cbea617f50" + integrity sha512-PzCr+a/KAef5ZawX7nbyNwBDtM1HdLIT53aSA2DDlxmxMngZ43O8SIePOeX8H5S+FHXeI6t97mTt/dDdzY4Fyw== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "7.9.0" - "@typescript-eslint/type-utils" "7.9.0" - "@typescript-eslint/utils" "7.9.0" - "@typescript-eslint/visitor-keys" "7.9.0" + "@typescript-eslint/scope-manager" "7.10.0" + "@typescript-eslint/type-utils" "7.10.0" + "@typescript-eslint/utils" "7.10.0" + "@typescript-eslint/visitor-keys" "7.10.0" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" @@ -1262,16 +1279,24 @@ debug "^4.3.4" "@typescript-eslint/parser@^7.1.1": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.9.0.tgz#fb3ba01b75e0e65cb78037a360961b00301f6c70" - integrity sha512-qHMJfkL5qvgQB2aLvhUSXxbK7OLnDkwPzFalg458pxQgfxKDfT1ZDbHQM/I6mDIf/svlMkj21kzKuQ2ixJlatQ== - dependencies: - "@typescript-eslint/scope-manager" "7.9.0" - "@typescript-eslint/types" "7.9.0" - "@typescript-eslint/typescript-estree" "7.9.0" - "@typescript-eslint/visitor-keys" "7.9.0" + version "7.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.10.0.tgz#e6ac1cba7bc0400a4459e7eb5b23115bd71accfb" + integrity sha512-2EjZMA0LUW5V5tGQiaa2Gys+nKdfrn2xiTIBLR4fxmPmVSvgPcKNW+AE/ln9k0A4zDUti0J/GZXMDupQoI+e1w== + dependencies: + "@typescript-eslint/scope-manager" "7.10.0" + "@typescript-eslint/types" "7.10.0" + "@typescript-eslint/typescript-estree" "7.10.0" + "@typescript-eslint/visitor-keys" "7.10.0" debug "^4.3.4" +"@typescript-eslint/scope-manager@7.10.0": + version "7.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.10.0.tgz#054a27b1090199337a39cf755f83d9f2ce26546b" + integrity sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg== + dependencies: + "@typescript-eslint/types" "7.10.0" + "@typescript-eslint/visitor-keys" "7.10.0" + "@typescript-eslint/scope-manager@7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz#cfb437b09a84f95a0930a76b066e89e35d94e3da" @@ -1280,33 +1305,39 @@ "@typescript-eslint/types" "7.2.0" "@typescript-eslint/visitor-keys" "7.2.0" -"@typescript-eslint/scope-manager@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.9.0.tgz#1dd3e63a4411db356a9d040e75864851b5f2619b" - integrity sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ== - dependencies: - "@typescript-eslint/types" "7.9.0" - "@typescript-eslint/visitor-keys" "7.9.0" - -"@typescript-eslint/type-utils@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.9.0.tgz#f523262e1b66ca65540b7a65a1222db52e0a90c9" - integrity sha512-6Qy8dfut0PFrFRAZsGzuLoM4hre4gjzWJB6sUvdunCYZsYemTkzZNwF1rnGea326PHPT3zn5Lmg32M/xfJfByA== +"@typescript-eslint/type-utils@7.10.0": + version "7.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.10.0.tgz#8a75accce851d0a331aa9331268ef64e9b300270" + integrity sha512-D7tS4WDkJWrVkuzgm90qYw9RdgBcrWmbbRkrLA4d7Pg3w0ttVGDsvYGV19SH8gPR5L7OtcN5J1hTtyenO9xE9g== dependencies: - "@typescript-eslint/typescript-estree" "7.9.0" - "@typescript-eslint/utils" "7.9.0" + "@typescript-eslint/typescript-estree" "7.10.0" + "@typescript-eslint/utils" "7.10.0" debug "^4.3.4" ts-api-utils "^1.3.0" +"@typescript-eslint/types@7.10.0": + version "7.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.10.0.tgz#da92309c97932a3a033762fd5faa8b067de84e3b" + integrity sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg== + "@typescript-eslint/types@7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.2.0.tgz#0feb685f16de320e8520f13cca30779c8b7c403f" integrity sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA== -"@typescript-eslint/types@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.9.0.tgz#b58e485e4bfba055659c7e683ad4f5f0821ae2ec" - integrity sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w== +"@typescript-eslint/typescript-estree@7.10.0": + version "7.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.10.0.tgz#6dcdc5de3149916a6a599fa89dde5c471b88b8bb" + integrity sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g== + dependencies: + "@typescript-eslint/types" "7.10.0" + "@typescript-eslint/visitor-keys" "7.10.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" "@typescript-eslint/typescript-estree@7.2.0": version "7.2.0" @@ -1322,29 +1353,23 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/typescript-estree@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.9.0.tgz#3395e27656060dc313a6b406c3a298b729685e07" - integrity sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg== +"@typescript-eslint/utils@7.10.0": + version "7.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.10.0.tgz#8ee43e5608c9f439524eaaea8de5b358b15c51b3" + integrity sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg== dependencies: - "@typescript-eslint/types" "7.9.0" - "@typescript-eslint/visitor-keys" "7.9.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - minimatch "^9.0.4" - semver "^7.6.0" - ts-api-utils "^1.3.0" + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "7.10.0" + "@typescript-eslint/types" "7.10.0" + "@typescript-eslint/typescript-estree" "7.10.0" -"@typescript-eslint/utils@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.9.0.tgz#1b96a34eefdca1c820cb1bbc2751d848b4540899" - integrity sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA== +"@typescript-eslint/visitor-keys@7.10.0": + version "7.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.10.0.tgz#2af2e91e73a75dd6b70b4486c48ae9d38a485a78" + integrity sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg== dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "7.9.0" - "@typescript-eslint/types" "7.9.0" - "@typescript-eslint/typescript-estree" "7.9.0" + "@typescript-eslint/types" "7.10.0" + eslint-visitor-keys "^3.4.3" "@typescript-eslint/visitor-keys@7.2.0": version "7.2.0" @@ -1354,14 +1379,6 @@ "@typescript-eslint/types" "7.2.0" eslint-visitor-keys "^3.4.1" -"@typescript-eslint/visitor-keys@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.9.0.tgz#82162656e339c3def02895f5c8546f6888d9b9ea" - integrity sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ== - dependencies: - "@typescript-eslint/types" "7.9.0" - eslint-visitor-keys "^3.4.3" - "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" @@ -3670,6 +3687,16 @@ language-tags@^1.0.9: dependencies: language-subtag-registry "^0.3.20" +leaflet-defaulticon-compatibility@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/leaflet-defaulticon-compatibility/-/leaflet-defaulticon-compatibility-0.1.2.tgz#f5e1a5841aeab9d1682d17887348855a741b3c2a" + integrity sha512-IrKagWxkTwzxUkFIumy/Zmo3ksjuAu3zEadtOuJcKzuXaD76Gwvg2Z1mLyx7y52ykOzM8rAH5ChBs4DnfdGa6Q== + +leaflet@^1.9.4: + version "1.9.4" + resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.9.4.tgz#23fae724e282fa25745aff82ca4d394748db7d8d" + integrity sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA== + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -4973,6 +5000,13 @@ react-is@^16.13.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-leaflet@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/react-leaflet/-/react-leaflet-4.2.1.tgz#c300e9eccaf15cb40757552e181200aa10b94780" + integrity sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q== + dependencies: + "@react-leaflet/core" "^2.1.0" + react-remove-scroll-bar@^2.3.3: version "2.3.6" resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz#3e585e9d163be84a010180b18721e851ac81a29c" @@ -5084,6 +5118,11 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +redaxios@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/redaxios/-/redaxios-0.5.1.tgz#a2e21c9337f615c23d8ceadb7c9f0a1844762d21" + integrity sha512-FSD2AmfdbkYwl7KDExYQlVvIrFz6Yd83pGfaGjBzM9F6rpq8g652Q4Yq5QD4c+nf4g2AgeElv1y+8ajUPiOYMg== + reflect.getprototypeof@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859"