upates on the google map removal

This commit is contained in:
2026-08-04 18:08:39 +05:30
parent c17057f693
commit 0a36212ac8
32 changed files with 3481 additions and 7372 deletions

View File

@@ -146,7 +146,7 @@ flowchart TD
direction LR direction LR
Store["Redux: fcm · login · menu · snackbar · toast · auth"]:::state Store["Redux: fcm · login · menu · snackbar · toast · auth"]:::state
QC["TanStack Query (cache + infinite scroll)"]:::state QC["TanStack Query (cache + infinite scroll)"]:::state
Env["REACT_APP_URL · REACT_APP_URL2 · REACT_APP_GOOGLE_MAPS_API_KEY"]:::state Env["REACT_APP_URL · REACT_APP_URL2"]:::state
LS["localStorage: authname · userid · roleid · userfcmtoken · applocations"]:::state LS["localStorage: authname · userid · roleid · userfcmtoken · applocations"]:::state
end end

3
.env
View File

@@ -4,13 +4,10 @@ GENERATE_SOURCEMAP = false
## Backend API URL ## Backend API URL
REACT_APP_API_URL=https://mock-data-api-nextjs.vercel.app/ REACT_APP_API_URL=https://mock-data-api-nextjs.vercel.app/
## Google Map Key
REACT_APP_URL=https://jupiter.nearle.app/live/api/v1 REACT_APP_URL=https://jupiter.nearle.app/live/api/v1
REACT_APP_URL2=https://jupiter.nearle.app/live/api/v2 REACT_APP_URL2=https://jupiter.nearle.app/live/api/v2
REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3 REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3
REACT_APP_STAFF_TOKEN= REACT_APP_STAFF_TOKEN=
REACT_APP_GOOGLE_MAPS_API_KEY=AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8
REACT_APP_RIDER_ACCESS_ID=AAAAILMpCEU:APA91bEavuOllBI6sFgYtxXAgNmAVwNA-MnCMHLGlR4_t7UqpLajAkdn3T0CZr_zaLBknLyim9ytFLMZgbeXmKqTad_PKCbqlYjHpaizVrLXtecxqyEy4UktIacK2UvHVUATHL-7VQQk REACT_APP_RIDER_ACCESS_ID=AAAAILMpCEU:APA91bEavuOllBI6sFgYtxXAgNmAVwNA-MnCMHLGlR4_t7UqpLajAkdn3T0CZr_zaLBknLyim9ytFLMZgbeXmKqTad_PKCbqlYjHpaizVrLXtecxqyEy4UktIacK2UvHVUATHL-7VQQk

View File

@@ -2,7 +2,6 @@ REACT_APP_URL=https://jupiter.nearle.app/live/api/v1
REACT_APP_URL2=https://jupiter.nearle.app/live/api/v2 REACT_APP_URL2=https://jupiter.nearle.app/live/api/v2
REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3 REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3
REACT_APP_STAFF_TOKEN= REACT_APP_STAFF_TOKEN=
REACT_APP_GOOGLE_MAPS_API_KEY=AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8
REACT_APP_RIDER_ACCESS_ID=AAAAILMpCEU:APA91bEavuOllBI6sFgYtxXAgNmAVwNA-MnCMHLGlR4_t7UqpLajAkdn3T0CZr_zaLBknLyim9ytFLMZgbeXmKqTad_PKCbqlYjHpaizVrLXtecxqyEy4UktIacK2UvHVUATHL-7VQQk REACT_APP_RIDER_ACCESS_ID=AAAAILMpCEU:APA91bEavuOllBI6sFgYtxXAgNmAVwNA-MnCMHLGlR4_t7UqpLajAkdn3T0CZr_zaLBknLyim9ytFLMZgbeXmKqTad_PKCbqlYjHpaizVrLXtecxqyEy4UktIacK2UvHVUATHL-7VQQk

View File

@@ -24,7 +24,7 @@ For the per-page API map and architectural flow chart, see the project skill **`
- **Routing**: `react-router-dom 6.10`, lazy-loaded via `components/Loadable`. - **Routing**: `react-router-dom 6.10`, lazy-loaded via `components/Loadable`.
- **Forms**: `formik 2.2` + `yup 1.1` where present; new simple forms can use plain `useState`. - **Forms**: `formik 2.2` + `yup 1.1` where present; new simple forms can use plain `useState`.
- **Dates**: `dayjs 1.11` with `utc` plugin (already extended at the top of `deliveries.js`). Use `dayjs(...).utc()` for backend timestamps and bare `dayjs(...)` for local-time bucketing — see the batch-bucketing comment in `deliveries.js` for the rationale. - **Dates**: `dayjs 1.11` with `utc` plugin (already extended at the top of `deliveries.js`). Use `dayjs(...).utc()` for backend timestamps and bare `dayjs(...)` for local-time bucketing — see the batch-bucketing comment in `deliveries.js` for the rationale.
- **Maps**: `leaflet` + `react-leaflet`, plus `@react-google-maps/api` for Google. Geocoding via `react-geocode`. Maps API key is `process.env.REACT_APP_GOOGLE_MAPS_API_KEY`. - **Maps**: `leaflet` + `react-leaflet` only. Geocoding/address search via free OSM Nominatim (`src/components/nearle_components/AddressAutocomplete.js`) and routing via OSRM — no API key required. Google Maps (`@react-google-maps/api`, `react-geocode`, `react-google-autocomplete`) has been fully removed; do not reintroduce it.
- **Notifications**: `firebase 10.14` (FCM) — see `src/firebase_notification/`. Toasts via `notistack 3`. - **Notifications**: `firebase 10.14` (FCM) — see `src/firebase_notification/`. Toasts via `notistack 3`.
- **Drag-and-drop**: `react-dnd` (used on the Dispatch Preview page). - **Drag-and-drop**: `react-dnd` (used on the Dispatch Preview page).
@@ -53,7 +53,7 @@ npm run lint
``` ```
- **Env files at repo root**: `env.staging` is committed; `.env.development` / `.env.production` are typically gitignored. Pull from a teammate when missing. - **Env files at repo root**: `env.staging` is committed; `.env.development` / `.env.production` are typically gitignored. Pull from a teammate when missing.
- **Required env vars**: `REACT_APP_URL` (primary API base), `REACT_APP_URL2` (secondary API base — used for `/users/update`, `/tenants/update`, `/partners/getriderlogs`, archival `/orders/getorders`), `REACT_APP_GOOGLE_MAPS_API_KEY`. The optimiser URLs (`routes.workolik.com`, `routemate.workolik.com`) and the Jupiter auth URL (`jupiter.nearle.app`) are hardcoded — see the `nearlexpress-docs` skill. - **Required env vars**: `REACT_APP_URL` (primary API base), `REACT_APP_URL2` (secondary API base — used for `/users/update`, `/tenants/update`, `/partners/getriderlogs`, archival `/orders/getorders`). No Maps API key is needed — maps and address search run on free Leaflet/OSM services. The optimiser URLs (`routes.workolik.com`, `routemate.workolik.com`) and the Jupiter auth URL (`jupiter.nearle.app`) are hardcoded — see the `nearlexpress-docs` skill.
- **Dev server runs on `http://localhost:3000`**. The user usually has it running already — assume it is up when reporting "reload to see it". - **Dev server runs on `http://localhost:3000`**. The user usually has it running already — assume it is up when reporting "reload to see it".
--- ---
@@ -282,7 +282,7 @@ These colour-code lifecycle states. Do **not** swap them for brand red — opera
- **The `applocationid` query param**: every list endpoint expects this — `0` means "All Zones". Pages default `appId = 0` and update it from `LocationAutocomplete`. - **The `applocationid` query param**: every list endpoint expects this — `0` means "All Zones". Pages default `appId = 0` and update it from `LocationAutocomplete`.
- **`role` gating** uses `localStorage.getItem('roleid')`. Some buttons are conditionally rendered based on it. Do not hide UI based on string equality alone — check existing patterns. - **`role` gating** uses `localStorage.getItem('roleid')`. Some buttons are conditionally rendered based on it. Do not hide UI based on string equality alone — check existing patterns.
- **Skeleton vs Loader vs LoaderWithImage** — these are different. Skeleton = per-row placeholder, Loader = full-screen backdrop blocking interaction, LoaderWithImage = inline branded spinner. Don't swap them. - **Skeleton vs Loader vs LoaderWithImage** — these are different. Skeleton = per-row placeholder, Loader = full-screen backdrop blocking interaction, LoaderWithImage = inline branded spinner. Don't swap them.
- **Maps API key** is read from env on every render in some places — wrapping it in a `useMemo` is fine but unnecessary. Don't add new direct `process.env.REACT_APP_GOOGLE_MAPS_API_KEY` reads outside map-related files. - **No Maps API key exists in this project anymore.** Address search/geocoding goes through `AddressAutocomplete.js` (Nominatim) and routing through OSRM — both free, no key. Do not add `process.env.REACT_APP_GOOGLE_MAPS_API_KEY` or any Google Maps script/dependency back in.
- **`Tenants.js` has known dangling references** (`setClientstatus`, `setState`, `setSuburb`, `setTenanatPricing`, `<Collapse in={open}>`) inherited from legacy code. They are tolerated. Do **not** "fix" them as a drive-by — they are out of scope and removing them risks breaking the row collapse contents. - **`Tenants.js` has known dangling references** (`setClientstatus`, `setState`, `setSuburb`, `setTenanatPricing`, `<Collapse in={open}>`) inherited from legacy code. They are tolerated. Do **not** "fix" them as a drive-by — they are out of scope and removing them risks breaking the row collapse contents.
--- ---

View File

@@ -162,7 +162,7 @@ flowchart TD
Store["Redux Toolkit store<br/>fcmSlice · loginUserSlice<br/>menu · snackbar · toastSlice · auth"]:::state Store["Redux Toolkit store<br/>fcmSlice · loginUserSlice<br/>menu · snackbar · toastSlice · auth"]:::state
QC["@tanstack/react-query<br/>QueryClient (cache + infinite scroll)"]:::state QC["@tanstack/react-query<br/>QueryClient (cache + infinite scroll)"]:::state
AxiosBase["axios (raw) +<br/>utils/axios.js (401 → /login)"]:::state AxiosBase["axios (raw) +<br/>utils/axios.js (401 → /login)"]:::state
Env["env vars: REACT_APP_URL ·<br/>REACT_APP_URL2 · REACT_APP_GOOGLE_MAPS_API_KEY"]:::state Env["env vars: REACT_APP_URL ·<br/>REACT_APP_URL2"]:::state
LS["localStorage:<br/>authname · userid · roleid ·<br/>userfcmtoken · applocations"]:::state LS["localStorage:<br/>authname · userid · roleid ·<br/>userfcmtoken · applocations"]:::state
Toasts["Notistack · OpenToast wrapper"]:::state Toasts["Notistack · OpenToast wrapper"]:::state
end end

View File

@@ -54,11 +54,10 @@ REACT_APP_API_URL=https://mock-data-api-nextjs.vercel.app/
REACT_APP_URL=https://jupiter.nearle.app/live/api/v1 REACT_APP_URL=https://jupiter.nearle.app/live/api/v1
REACT_APP_URL2=https://jupiter.nearle.app/live/api/v2 REACT_APP_URL2=https://jupiter.nearle.app/live/api/v2
REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3 REACT_APP_URL3=https://jupiter.nearle.app/live/api/v3
# API Credentials
REACT_APP_GOOGLE_MAPS_API_KEY=AIzaSyCF...
``` ```
No Maps API key is required — maps and address search run on free Leaflet/OpenStreetMap (Nominatim + OSRM), not Google Maps.
--- ---
## 🏃 Getting Started & Local Development ## 🏃 Getting Started & Local Development

112
package-lock.json generated
View File

@@ -20,7 +20,6 @@
"@mui/lab": "^5.0.0-alpha.127", "@mui/lab": "^5.0.0-alpha.127",
"@mui/material": "^5.12.1", "@mui/material": "^5.12.1",
"@mui/x-date-pickers": "^7.29.4", "@mui/x-date-pickers": "^7.29.4",
"@react-google-maps/api": "^2.20.7",
"@reduxjs/toolkit": "^2.12.0", "@reduxjs/toolkit": "^2.12.0",
"@stylexjs/stylex": "^0.19.0", "@stylexjs/stylex": "^0.19.0",
"@svgr/webpack": "^7.0.0", "@svgr/webpack": "^7.0.0",
@@ -52,8 +51,6 @@
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1", "react-dnd-html5-backend": "^16.0.1",
"react-dom": "^19.2.8", "react-dom": "^19.2.8",
"react-geocode": "^0.2.3",
"react-google-autocomplete": "^2.7.3",
"react-icons": "^4.12.0", "react-icons": "^4.12.0",
"react-intl": "^7.1.14", "react-intl": "^7.1.14",
"react-leaflet": "^5.0.0", "react-leaflet": "^5.0.0",
@@ -3586,22 +3583,6 @@
"tslib": "^2.8.0" "tslib": "^2.8.0"
} }
}, },
"node_modules/@googlemaps/js-api-loader": {
"version": "1.16.8",
"resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.16.8.tgz",
"integrity": "sha512-CROqqwfKotdO6EBjZO/gQGVTbeDps5V7Mt9+8+5Q+jTg5CRMi3Ii/L9PmV3USROrt2uWxtGzJHORmByxyo9pSQ==",
"license": "Apache-2.0"
},
"node_modules/@googlemaps/markerclusterer": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/@googlemaps/markerclusterer/-/markerclusterer-2.5.3.tgz",
"integrity": "sha512-x7lX0R5yYOoiNectr10wLgCBasNcXFHiADIBdmn7jQllF2B5ENQw5XtZK+hIw4xnV0Df0xhN4LN98XqA5jaiOw==",
"license": "Apache-2.0",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"supercluster": "^8.0.1"
}
},
"node_modules/@grpc/grpc-js": { "node_modules/@grpc/grpc-js": {
"version": "1.9.14", "version": "1.9.14",
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz",
@@ -5106,36 +5087,6 @@
"integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==", "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@react-google-maps/api": {
"version": "2.20.7",
"resolved": "https://registry.npmjs.org/@react-google-maps/api/-/api-2.20.7.tgz",
"integrity": "sha512-ys7uri3V6gjhYZUI43srHzSKDC6/jiKTwHNlwXFTvjeaJE3M3OaYBt9FZKvJs8qnOhL6i6nD1BKJoi1KrnkCkg==",
"license": "MIT",
"dependencies": {
"@googlemaps/js-api-loader": "1.16.8",
"@googlemaps/markerclusterer": "2.5.3",
"@react-google-maps/infobox": "2.20.0",
"@react-google-maps/marker-clusterer": "2.20.0",
"@types/google.maps": "3.58.1",
"invariant": "2.2.4"
},
"peerDependencies": {
"react": "^16.8 || ^17 || ^18 || ^19",
"react-dom": "^16.8 || ^17 || ^18 || ^19"
}
},
"node_modules/@react-google-maps/infobox": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/@react-google-maps/infobox/-/infobox-2.20.0.tgz",
"integrity": "sha512-03PJHjohhaVLkX6+NHhlr8CIlvUxWaXhryqDjyaZ8iIqqix/nV8GFdz9O3m5OsjtxtNho09F/15j14yV0nuyLQ==",
"license": "MIT"
},
"node_modules/@react-google-maps/marker-clusterer": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/@react-google-maps/marker-clusterer/-/marker-clusterer-2.20.0.tgz",
"integrity": "sha512-tieX9Va5w1yP88vMgfH1pHTacDQ9TgDTjox3tLlisKDXRQWdjw+QeVVghhf5XqqIxXHgPdcGwBvKY6UP+SIvLw==",
"license": "MIT"
},
"node_modules/@react-leaflet/core": { "node_modules/@react-leaflet/core": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz", "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz",
@@ -5767,12 +5718,6 @@
"@types/range-parser": "*" "@types/range-parser": "*"
} }
}, },
"node_modules/@types/google.maps": {
"version": "3.58.1",
"resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.58.1.tgz",
"integrity": "sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==",
"license": "MIT"
},
"node_modules/@types/graceful-fs": { "node_modules/@types/graceful-fs": {
"version": "4.1.5", "version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
@@ -14158,12 +14103,6 @@
"integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/kdbush": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz",
"integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==",
"license": "ISC"
},
"node_modules/keyv": { "node_modules/keyv": {
"version": "4.5.4", "version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -18142,34 +18081,6 @@
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==", "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/react-geocode": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/react-geocode/-/react-geocode-0.2.3.tgz",
"integrity": "sha512-sIpbgmn1IUzAxO4haOZ6jeeFnMD8ya9PC38yiNrmJ9vPWbvAO2D/2yfCBzZjGZVUm4PRzKAc0KghXfaEnug0TQ==",
"license": "MIT",
"dependencies": {
"regenerator-runtime": "^0.13.3"
}
},
"node_modules/react-geocode/node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
"license": "MIT"
},
"node_modules/react-google-autocomplete": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/react-google-autocomplete/-/react-google-autocomplete-2.7.4.tgz",
"integrity": "sha512-BeEk2mjzgJcfiCueuKBofm5+RxHUIr0+POn9Yw8merK4Yd0jcOp9Lk/IGJySbz1GTi2Jqvi7V4dbw/DPLD1HMA==",
"license": "ISC",
"dependencies": {
"lodash.debounce": "^4.0.8",
"prop-types": "^15.5.0"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/react-icons": { "node_modules/react-icons": {
"version": "4.12.0", "version": "4.12.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz",
@@ -20719,15 +20630,6 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/supercluster": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz",
"integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==",
"license": "ISC",
"dependencies": {
"kdbush": "^4.0.2"
}
},
"node_modules/supports-color": { "node_modules/supports-color": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -21444,20 +21346,6 @@
"is-typedarray": "^1.0.0" "is-typedarray": "^1.0.0"
} }
}, },
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/ua-parser-js": { "node_modules/ua-parser-js": {
"version": "1.0.40", "version": "1.0.40",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz",

View File

@@ -15,7 +15,6 @@
"@mui/lab": "^5.0.0-alpha.127", "@mui/lab": "^5.0.0-alpha.127",
"@mui/material": "^5.12.1", "@mui/material": "^5.12.1",
"@mui/x-date-pickers": "^7.29.4", "@mui/x-date-pickers": "^7.29.4",
"@react-google-maps/api": "^2.20.7",
"@reduxjs/toolkit": "^2.12.0", "@reduxjs/toolkit": "^2.12.0",
"@stylexjs/stylex": "^0.19.0", "@stylexjs/stylex": "^0.19.0",
"@svgr/webpack": "^7.0.0", "@svgr/webpack": "^7.0.0",
@@ -47,8 +46,6 @@
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1", "react-dnd-html5-backend": "^16.0.1",
"react-dom": "^19.2.8", "react-dom": "^19.2.8",
"react-geocode": "^0.2.3",
"react-google-autocomplete": "^2.7.3",
"react-icons": "^4.12.0", "react-icons": "^4.12.0",
"react-intl": "^7.1.14", "react-intl": "^7.1.14",
"react-leaflet": "^5.0.0", "react-leaflet": "^5.0.0",

View File

@@ -39,10 +39,6 @@
<!-- this is to resolve issue in old safari browser in tablet --> <!-- this is to resolve issue in old safari browser in tablet -->
<script src="https://cdn.jsdelivr.net/npm/resize-observer-polyfill@1.5.1/dist/ResizeObserver.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/resize-observer-polyfill@1.5.1/dist/ResizeObserver.min.js"></script>
<!-- google address autocomplete -->
<!-- <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDQ2c_pOSOFYSjxGMwkFvCVWKjYOM9siow&libraries=places"></script> -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBhkGfnq27sN0wV5y_S-M2KojpFTk_by-Q&libraries=places"></script>
<style> <style>
.datedialog > div > div > .MuiPaper-root { .datedialog > div > div > .MuiPaper-root {
box-shadow: none !important; box-shadow: none !important;

View File

@@ -0,0 +1,193 @@
import React, { useEffect, useMemo, useState } from 'react';
import { Autocomplete, TextField, CircularProgress } from '@mui/material';
import { debounce } from '@mui/material/utils';
// Free OSM Nominatim geocoder — replaces Google Places Autocomplete /
// react-geocode across the console. No API key required. Nominatim's usage
// policy caps the public endpoint at ~1 req/sec, so every caller here is
// debounced (500ms) and cancels stale in-flight predictions.
const NOMINATIM_SEARCH_URL = 'https://nominatim.openstreetmap.org/search';
// Builds a Google-Places-shaped `address_components` array (each entry
// `{ long_name, short_name, types: [] }`) from Nominatim's flat `address`
// object, so existing call sites' `place.address_components.forEach(...)`
// type-switch parsing keeps working unchanged.
const buildAddressComponents = (addr = {}) => {
const components = [];
const push = (longName, types) => {
if (longName) components.push({ long_name: longName, short_name: longName, types });
};
push(addr.house_number, ['street_number']);
push(addr.road || addr.pedestrian, ['route']);
push(addr.suburb || addr.neighbourhood || addr.quarter, ['sublocality_level_1', 'sublocality']);
push(addr.city_district || addr.county, ['administrative_area_level_3']);
push(addr.city || addr.town || addr.village, ['locality']);
push(addr.state, ['administrative_area_level_1']);
push(addr.country, ['country']);
push(addr.postcode, ['postal_code']);
return components;
};
// Shapes a Nominatim result close enough to a Google Places `place` object
// (formatted_address, geometry.location.lat()/lng(), address_components)
// that call sites need only mechanical edits, not rewrites.
export const toPlace = (result) => ({
formatted_address: result.display_name,
name: result.display_name?.split(',')[0] || '',
geometry: {
location: {
lat: () => parseFloat(result.lat),
lng: () => parseFloat(result.lon)
}
},
address_components: buildAddressComponents(result.address)
});
const buildParams = (query, bias) => {
const params = new URLSearchParams({ q: query, format: 'json', addressdetails: '1', limit: '5' });
if (bias?.lat && bias?.lng) {
const d = 0.5; // ~55km box around the operator's zone — soft bias, not a hard filter
params.set('viewbox', `${bias.lng - d},${bias.lat + d},${bias.lng + d},${bias.lat - d}`);
}
return params;
};
// Standalone forward-geocode helper — replaces `Geocode.fromAddress(address)`
// for call sites that resolve a plain text address without a predictions
// dropdown (e.g. re-geocoding on submit). Returns a `toPlace`-shaped object,
// or null if nothing matched.
export async function geocodeAddress(address, { bias } = {}) {
if (!address) return null;
try {
const params = buildParams(address, bias);
params.set('limit', '1');
const res = await fetch(`${NOMINATIM_SEARCH_URL}?${params.toString()}`, { headers: { Accept: 'application/json' } });
if (!res.ok) return null;
const results = await res.json();
if (!results?.length) return null;
return toPlace(results[0]);
} catch (err) {
console.error('geocodeAddress error:', err);
return null;
}
}
// Address search-as-you-type — replaces Google Places Autocomplete
// (usePlacesWidget / window.google.maps.places.Autocomplete /
// AutocompleteService) across the console. Renders as an MUI Autocomplete
// with freeSolo so the operator can still submit free text.
//
// Props:
// value / onChange(text) — controlled free-text input value
// onPlaceSelected(place) — fired when a suggestion is chosen; `place`
// is shaped like a Google Places `place`
// bias { lat, lng } — optional soft bias toward the operator's zone
const AddressAutocomplete = ({
id,
label,
placeholder = 'Search address',
value,
onChange,
onPlaceSelected,
bias,
sx,
textFieldSx,
fullWidth = true,
disabled,
inputRef,
TextFieldProps = {}
}) => {
const [inputValue, setInputValue] = useState(value || '');
const [options, setOptions] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (value !== undefined && value !== inputValue) setInputValue(value || '');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [value]);
const fetchPredictions = useMemo(
() =>
debounce((query, bias1, callback) => {
if (!query) {
callback([]);
return;
}
const params = buildParams(query, bias1);
fetch(`${NOMINATIM_SEARCH_URL}?${params.toString()}`, { headers: { Accept: 'application/json' } })
.then((res) => (res.ok ? res.json() : []))
.then((results) => callback(results || []))
.catch(() => callback([]));
}, 500),
[]
);
useEffect(() => {
let active = true;
if (!inputValue) {
setOptions([]);
setLoading(false);
return undefined;
}
setLoading(true);
fetchPredictions(inputValue, bias, (results) => {
if (!active) return;
setLoading(false);
setOptions(results);
});
return () => {
active = false;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [inputValue, bias?.lat, bias?.lng, fetchPredictions]);
return (
<Autocomplete
id={id}
freeSolo
fullWidth={fullWidth}
disabled={disabled}
sx={sx}
options={options}
filterOptions={(x) => x}
getOptionLabel={(option) => (typeof option === 'string' ? option : option.display_name || '')}
isOptionEqualToValue={(option, val) => option.place_id === val?.place_id}
inputValue={inputValue}
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue);
onChange?.(newInputValue);
}}
onChange={(event, selected) => {
if (selected && typeof selected !== 'string') {
setInputValue(selected.display_name || '');
onPlaceSelected?.(toPlace(selected));
}
}}
renderInput={(params) => (
<TextField
{...params}
{...TextFieldProps}
inputRef={inputRef}
label={label}
placeholder={placeholder}
sx={textFieldSx}
autoComplete="off"
InputProps={{
...params.InputProps,
...TextFieldProps.InputProps,
startAdornment: TextFieldProps.InputProps?.startAdornment ?? params.InputProps.startAdornment,
endAdornment: (
<>
{loading ? <CircularProgress color="inherit" size={16} /> : null}
{TextFieldProps.InputProps?.endAdornment ?? params.InputProps.endAdornment}
</>
)
}}
/>
)}
/>
);
};
export default AddressAutocomplete;

View File

@@ -59,15 +59,14 @@ const AppSideNav = ({ isCollapsed, onCollapsedChange }) => {
paddingBlock: '12px', paddingBlock: '12px',
paddingInline: '8px', paddingInline: '8px',
boxSizing: 'border-box', boxSizing: 'border-box',
'--spacing-12': '72px', '--spacing-12': '72px'
// Pages with tall/independently-scrolling content (e.g. deliveries' // Sticky positioning + height/scroll are already handled by
// internal TableContainer scroll region) still let the document // AppShell's own auto-mode side nav wrapper (position: sticky,
// scroll past the header, so pin the nav explicitly rather than // top/height driven by --appshell-header-height, see
// relying only on AppShell's own auto-mode sticky wrapper. // AppTopNav.js). A second nested position: sticky here — inside
position: 'sticky', // that wrapper's own scrollable LayoutPanel — was redundant and
top: 'var(--appshell-header-height, 0px)', // gave the offset two independent calculations to drift apart on,
height: 'calc(100dvh - var(--appshell-header-height, 0px))', // which is what caused the visible jump/scroll-away glitch.
overflowY: 'auto'
}} }}
> >
<SideNavSection title="Doormile">{nearle.children.map(renderMenuItem)}</SideNavSection> <SideNavSection title="Doormile">{nearle.children.map(renderMenuItem)}</SideNavSection>

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react'; import { useLayoutEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
@@ -89,14 +89,15 @@ const AppTopNav = () => {
// AppShell (height="auto") pins the sticky side nav below the header using // AppShell (height="auto") pins the sticky side nav below the header using
// a --appshell-header-height CSS var it measures itself via ResizeObserver // a --appshell-header-height CSS var it measures itself via ResizeObserver
// (AppShell.tsx). On some routes that measurement lags/settles wrong, so // (AppShell.tsx), inside a useEffect that only runs (and paints) *after*
// the side nav's sticky offset is off and its bottom-anchored collapse // the first frame. That one-frame gap is what made the side nav's sticky
// button visibly jumps on scroll. Re-measure the header independently here // offset settle wrong and visibly jump/drift on scroll. Re-measure the
// and force the same variable with !important on the shell root — an // header independently here in useLayoutEffect (synchronous, before the
// author-stylesheet !important rule beats AppShell's own non-important // browser paints) and force the same variable with !important on the
// inline style.setProperty() call on that same element, so this always // shell root — an author-stylesheet !important rule beats AppShell's own
// wins regardless of what the internal measurement produced. // non-important inline style.setProperty() call on that same element, so
useEffect(() => { // this always wins regardless of what the internal measurement produced.
useLayoutEffect(() => {
const el = topNavRef.current; const el = topNavRef.current;
if (!el) return undefined; if (!el) return undefined;

View File

@@ -22,7 +22,9 @@ import {
PartitionOutlined, PartitionOutlined,
CarOutlined, CarOutlined,
UserOutlined, UserOutlined,
ProfileOutlined ProfileOutlined,
TeamOutlined,
MoneyCollectOutlined
} from '@ant-design/icons'; } from '@ant-design/icons';
// icons // icons
@@ -46,7 +48,9 @@ const icons = {
PartitionOutlined, PartitionOutlined,
CarOutlined, CarOutlined,
UserOutlined, UserOutlined,
ProfileOutlined ProfileOutlined,
TeamOutlined,
MoneyCollectOutlined
}; };
// ==============================|| MENU ITEMS - SUPPORT ||============================== // // ==============================|| MENU ITEMS - SUPPORT ||============================== //
@@ -85,6 +89,20 @@ const nearle = {
url: '/doormile/riders', url: '/doormile/riders',
icon: icons.UserOutlined icon: icons.UserOutlined
}, },
{
id: 'tenants',
title: <FormattedMessage id="tenants" />,
type: 'item',
url: '/doormile/tenants',
icon: icons.TeamOutlined
},
{
id: 'pricing',
title: <FormattedMessage id="pricing" />,
type: 'item',
url: '/doormile/pricing',
icon: icons.MoneyCollectOutlined
},
{ {
id: 'reports', id: 'reports',
title: <FormattedMessage id="reports" />, title: <FormattedMessage id="reports" />,

View File

@@ -363,6 +363,62 @@ export const updateDeliveryAPI = async (orderData) => {
return axios.put(`${process.env.REACT_APP_URL}/deliveries/updatedelivery`, orderData); return axios.put(`${process.env.REACT_APP_URL}/deliveries/updatedelivery`, orderData);
}; };
// ==============================|| getalltenants (tenants) ||============================== //
export const getalltenants = async ({ queryKey }) => {
const [, appId, debouncedSearch, status, page, rowsPerPage] = queryKey;
try {
let url = `${process.env.REACT_APP_URL
}/tenants/getalltenants/?status=${status}&applocationid=${appId}&keyword=${debouncedSearch}&pageno=${page + 1
}&pagesize=${rowsPerPage}&moduleid=6`;
const response = await axios.get(url);
return response.data.details; // return only data, keep it clean
} catch (err) {
const message = err.response?.data?.message || err.message || 'Something went wrong';
OpenToast(message);
return null; // return null for failure
}
};
// ==============================|| gettenantsummary (tenants) ||============================== //
export const gettenantsummary = async ({ queryKey }) => {
const [, appId] = queryKey;
try {
const response = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantsummary/?moduleid=6&applocationid=${appId}`);
return response.data.summary; // return only data, keep it clean
} catch (err) {
const message = err.response?.data?.message || err.message || 'Something went wrong';
OpenToast(message);
return null; // return null for failure
}
};
// ==============================|| getpricinglist (tenants) ||============================== //
export const getpricinglist = async ({ queryKey }) => {
const [, appId] = queryKey;
try {
const response = await axios.get(`${process.env.REACT_APP_URL}/tenants/getpricinglist/?moduleid=6&applocationid=${appId}`);
return response.data.summary; // return only data, keep it clean
} catch (err) {
const message = err.response?.data?.message || err.message || 'Something went wrong';
OpenToast(message);
return null; // return null for failure
}
};
// ==============================|| getallpricing (clientPricing) ||============================== //
export const getallpricing = async ({ queryKey }) => {
const [, appId] = queryKey;
try {
const response = await axios.get(`${process.env.REACT_APP_URL}/utils/getallpricing/?applocationid=${appId}`);
return response.data.details || [];
} catch (err) {
const message = err.response?.data?.message || err.message || 'Something went wrong';
OpenToast(message);
return [];
}
};
// ==============================|| fetchAllRiders (riders) ||============================== // // ==============================|| fetchAllRiders (riders) ||============================== //
export const fetchAllRiders = async ({ pageParam = 1, queryKey }) => { export const fetchAllRiders = async ({ pageParam = 1, queryKey }) => {
try { try {

View File

@@ -0,0 +1,602 @@
import React, { useMemo, useRef, useState } from 'react';
import {
Avatar,
Box,
Grid,
Paper,
Stack,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography,
useMediaQuery,
useTheme
} from '@mui/material';
import {
MdLocalOffer,
MdMyLocation,
MdAttachMoney,
MdGroups,
MdPlace,
MdSpeed,
MdPriceCheck,
MdStraighten,
MdReceiptLong,
MdOutlineLocalOffer,
MdOutlineGroups,
MdOutlineAttachMoney,
MdOutlinePlace
} from 'react-icons/md';
import { useQuery } from '@tanstack/react-query';
import Loader from 'components/Loader';
import DebounceSearchBar from 'components/nearle_components/DebounceSearchBar';
import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete';
import PageHeader from 'components/nearle_components/PageHeader';
import StatCard from 'components/nearle_components/StatCard';
import { MobileCard, MobileCardList, MobileField, MobileFieldGrid } from 'components/nearle_components/MobileCard';
import { OrdersTableSkeleton } from '../orders/OrdersTableSkeleton';
import { getallpricing } from 'pages/api/api';
// ============================================================================
// Design tokens — shared with the deliveries / tenants / customers pages so every
// surface (header, KPI tiles, table, badges) speaks the same visual language.
// Keep this block in sync with customers.js / deliveries.js.
// ============================================================================
const DT = {
radiusPill: 999,
radiusCard: 14,
radiusField: 10,
shadowSoft: '0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px rgba(15, 23, 42, 0.05)',
shadowMd: '0 1px 3px rgba(15, 23, 42, 0.06)',
shadowPop: '0 12px 32px rgba(15, 23, 42, 0.12)',
textPrimary: '#0f172a',
textSecondary: '#64748b',
textMuted: '#94a3b8',
borderSubtle: '#e2e8f0',
borderHover: '#cbd5e1',
divider: '#f1f5f9',
surface: '#ffffff',
surfaceAlt: '#f8fafc',
brand: '#662582'
};
const a = (c, suffix) => `${c}${suffix}`;
const tint = (c) => a(c, '08');
const soft = (c) => a(c, '18');
const ring = (c) => a(c, '26');
const edge = (c) => a(c, '55');
const BRAND = '#662582';
const SoftPaper = (props) => (
<Paper
{...props}
sx={{
mt: 0.75,
borderRadius: 2,
boxShadow: DT.shadowPop,
border: '1px solid',
borderColor: 'divider',
overflow: 'hidden'
}}
/>
);
const AccentAvatar = ({ color, selected, size = 24, children }) => (
<Avatar
sx={{
width: size,
height: size,
bgcolor: selected ? color : soft(color),
color: selected ? '#fff' : color,
transition: 'background-color 0.15s, color 0.15s'
}}
>
{children}
</Avatar>
);
const formatRupees = (value) =>
new Intl.NumberFormat('en-IN', {
style: 'currency',
currency: 'INR',
minimumFractionDigits: 2
}).format(Number(value) || 0);
const formatDecimal = (value) =>
new Intl.NumberFormat('en-IN', { minimumFractionDigits: 2 }).format(Number(value) || 0);
// Numeric table value — plain, strong, right-readable text. The old version
// wrapped every cell in a coloured bordered pill, which made the table read
// like a rainbow; corporate data tables keep figures as quiet typography and
// let the column header carry the meaning.
const MetricPill = ({ label }) => (
<Typography
component="span"
sx={{ fontSize: 13.5, fontWeight: 700, color: DT.textPrimary, whiteSpace: 'nowrap', fontVariantNumeric: 'tabular-nums' }}
>
{label}
</Typography>
);
// Subtle neutral category chip (zone / slab) — one quiet style, muted icon.
const CategoryChip = ({ icon, label }) => (
<Box
sx={{
display: 'inline-flex',
alignItems: 'center',
gap: 0.5,
px: 1,
py: 0.375,
borderRadius: 8,
bgcolor: DT.surfaceAlt,
border: `1px solid ${DT.borderSubtle}`,
color: DT.textPrimary,
fontSize: 12,
fontWeight: 600,
whiteSpace: 'nowrap'
}}
>
<Box component="span" sx={{ display: 'inline-flex', color: DT.textMuted }}>
{icon}
</Box>
{label}
</Box>
);
// ==============================|| Pricing page ||============================== //
const ClientsPricing = () => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const containerRef = useRef();
const [appId, setAppId] = useState(0);
const [locaName, setLocoName] = useState('All');
const [searchword, setSearchword] = useState('');
const [debouncedSearch, setDebouncedSearch] = useState('');
const {
data: pricing = [],
isLoading
} = useQuery({
queryKey: ['getallpricing', appId],
queryFn: getallpricing,
keepPreviousData: true
});
const rows = useMemo(() => {
if (!debouncedSearch) return pricing;
const q = debouncedSearch.toLowerCase().trim();
return pricing.filter((row) =>
[row.applocation, row.appname, row.slab, String(row.pricingid)]
.filter(Boolean)
.some((field) => String(field).toLowerCase().includes(q))
);
}, [pricing, debouncedSearch]);
const stats = useMemo(() => {
const total = pricing.length;
const tenants = new Set(pricing.map((r) => r.appname).filter(Boolean)).size;
const avgBase = total
? pricing.reduce((sum, r) => sum + (Number(r.baseprice) || 0), 0) / total
: 0;
return { total, tenants, avgBase };
}, [pricing]);
const KPI_META = [
{ key: 'total', label: 'Total Pricing Slabs', color: BRAND, icon: MdOutlineLocalOffer, value: stats.total },
{ key: 'tenants', label: 'Tenants Priced', color: '#0ea5e9', icon: MdOutlineGroups, value: stats.tenants },
{ key: 'avg', label: 'Avg Base Price', color: '#f59e0b', icon: MdOutlineAttachMoney, value: formatRupees(stats.avgBase) },
{ key: 'zone', label: 'Active Zone', color: '#10b981', icon: MdOutlinePlace, value: locaName || 'All Zones' }
];
return (
<>
{isLoading && <Loader />}
{/* ============================================= || Header || ============================================= */}
<PageHeader
title="Pricing"
subtitle={`Live · ${locaName || 'All Zones'}`}
live
action={
<LocationAutocomplete
locaName={locaName}
setAppId={setAppId}
setLocoName={setLocoName}
pill
accentColor={BRAND}
icon={<MdMyLocation size={14} />}
placeholder="Select Zone"
paperComponent={SoftPaper}
sx={{ width: { xs: '100%', sm: 280 }, zIndex: 100 }}
/>
}
/>
{/* ============================================= || KPI Cards || ============================================= */}
<Grid container spacing={{ xs: 2, md: 2.5 }} sx={{ mb: { xs: 1.5, md: 2 } }}>
{KPI_META.map((item) => {
const Icon = item.icon;
return (
<Grid item key={item.key} xs={6} sm={6} md={3}>
<StatCard title={item.label} value={item.value} icon={<Icon size={20} />} color={item.color} />
</Grid>
);
})}
</Grid>
{/* ============================================= || Search Header || ============================================= */}
<Paper
elevation={0}
sx={{
mt: { xs: 1.5, md: 2 },
p: { xs: 1, md: 1.5 },
borderTopLeftRadius: DT.radiusCard / 8,
borderTopRightRadius: DT.radiusCard / 8,
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
border: '1px solid',
borderColor: DT.borderSubtle,
borderBottom: 0,
background: '#fff'
}}
>
<Stack
direction={{ xs: 'column', sm: 'row' }}
alignItems={{ xs: 'stretch', sm: 'center' }}
justifyContent="space-between"
spacing={1.25}
>
<Stack direction="row" alignItems="center" spacing={1.25}>
<AccentAvatar color={BRAND} size={32}>
<MdLocalOffer size={18} />
</AccentAvatar>
<Stack>
<Typography
variant="caption"
sx={{ fontWeight: 800, color: DT.textSecondary, letterSpacing: 0.6, textTransform: 'uppercase' }}
>
Pricing Catalog
</Typography>
<Typography variant="body2" sx={{ color: DT.textPrimary, fontWeight: 700 }}>
{pricing.length} total · {rows.length} shown
</Typography>
</Stack>
</Stack>
<Box sx={{ width: { xs: '100%', sm: 280, lg: 340 }, flex: { xs: '1 1 100%', sm: '0 0 auto' } }}>
<DebounceSearchBar
value={searchword}
onChange={setSearchword}
onDebouncedChange={setDebouncedSearch}
placeholder={`Search pricing (ctrl+k)`}
sx={{
m: 0,
width: '100%',
borderRadius: DT.radiusField + 'px',
bgcolor: DT.surface,
'& fieldset': { borderColor: DT.borderSubtle, borderWidth: 1 },
'&:hover fieldset': { borderColor: DT.borderHover },
'&.Mui-focused fieldset': { borderColor: BRAND, borderWidth: 1.5 },
'&.Mui-focused': { boxShadow: `0 0 0 3px ${ring(BRAND)}` }
}}
/>
</Box>
</Stack>
</Paper>
{/* ============================================= || Table || ============================================= */}
<Paper
elevation={0}
sx={{
borderTopLeftRadius: 0,
borderTopRightRadius: 0,
borderBottomLeftRadius: DT.radiusCard / 8,
borderBottomRightRadius: DT.radiusCard / 8,
border: '1px solid',
borderColor: DT.borderSubtle,
overflow: 'hidden',
background: '#fff'
}}
>
{isMobile ? (
rows.length === 0 && !isLoading ? (
<Stack alignItems="center" spacing={1.5} sx={{ py: 6, px: 2 }}>
<Avatar sx={{ width: 64, height: 64, bgcolor: soft('#94a3b8'), color: DT.textMuted }}>
<MdLocalOffer size={28} />
</Avatar>
<Typography variant="subtitle1" sx={{ fontWeight: 700, color: DT.textPrimary }}>
No pricing to show
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary, textAlign: 'center' }}>
{searchword ? 'Try a different keyword.' : 'Pick a zone above to load the catalog.'}
</Typography>
</Stack>
) : (
<MobileCardList scroll>
{rows.map((row, index) => (
<MobileCard
key={row.pricingid || `${row.appname}-${index}`}
accent={BRAND}
header={
<Stack direction="row" alignItems="center" justifyContent="space-between" spacing={1}>
<Stack direction="row" alignItems="center" spacing={1} sx={{ minWidth: 0 }}>
<AccentAvatar color={BRAND} size={36}>
<MdGroups size={18} />
</AccentAvatar>
<Stack sx={{ minWidth: 0 }}>
<Typography
variant="subtitle2"
sx={{ fontWeight: 700, color: DT.textPrimary }}
noWrap
>
{row.appname || '—'}
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary }}>
ID #{row.pricingid}
</Typography>
</Stack>
</Stack>
<Typography variant="caption" sx={{ fontWeight: 700, color: DT.textMuted, flexShrink: 0 }}>
{String(index + 1).padStart(2, '0')}
</Typography>
</Stack>
}
>
<Stack direction="row" spacing={0.75} sx={{ mt: 1, flexWrap: 'wrap', gap: 0.75 }}>
{row.applocation ? (
<Box
sx={{
display: 'inline-flex',
alignItems: 'center',
gap: 0.5,
px: 1,
py: 0.375,
borderRadius: 999,
bgcolor: tint('#10b981'),
border: `1px solid ${edge('#10b981')}`,
color: '#10b981',
fontSize: 11,
fontWeight: 800
}}
>
<MdPlace size={12} /> {row.applocation}
</Box>
) : null}
<Box
sx={{
display: 'inline-flex',
alignItems: 'center',
gap: 0.5,
px: 1,
py: 0.375,
borderRadius: 999,
bgcolor: tint('#0ea5e9'),
border: `1px solid ${edge('#0ea5e9')}`,
color: '#0ea5e9',
fontSize: 11,
fontWeight: 800
}}
>
<MdSpeed size={12} /> {row.slab || '—'}
</Box>
</Stack>
<MobileFieldGrid>
<MobileField label="Base Price">
<MetricPill
color={BRAND}
icon={<MdPriceCheck size={12} />}
label={formatRupees(row.baseprice)}
/>
</MobileField>
<MobileField label="Price / KM">
<MetricPill
color="#10b981"
icon={<MdAttachMoney size={12} />}
label={formatRupees(row.priceperkm)}
/>
</MobileField>
<MobileField label="Min KM">
<MetricPill
color="#f59e0b"
icon={<MdStraighten size={12} />}
label={`${formatDecimal(row.minkm)} km`}
/>
</MobileField>
<MobileField label="Max KM">
<MetricPill
color="#ef4444"
icon={<MdStraighten size={12} />}
label={`${formatDecimal(row.maxkm)} km`}
/>
</MobileField>
<MobileField label="Min Orders">
<Stack direction="row" alignItems="center" spacing={0.5}>
<MdReceiptLong size={14} color={DT.textMuted} />
<Typography variant="subtitle2" sx={{ fontWeight: 700, color: DT.textPrimary }}>
{row.minorder ?? '—'}
</Typography>
</Stack>
</MobileField>
</MobileFieldGrid>
</MobileCard>
))}
</MobileCardList>
)
) : (
<TableContainer
ref={containerRef}
sx={{
maxHeight: { xs: 'calc(100vh - 220px)', md: 'calc(100vh - 190px)' },
'&::-webkit-scrollbar': { width: 10, height: 10 },
'&::-webkit-scrollbar-thumb': {
backgroundColor: edge(BRAND),
borderRadius: 8,
'&:hover': { backgroundColor: BRAND }
},
'&::-webkit-scrollbar-track': { backgroundColor: DT.surfaceAlt }
}}
>
<Table stickyHeader sx={{ minWidth: { xs: 860, md: 1080 } }}>
<TableHead>
<TableRow
sx={{
'& th': {
backgroundColor: DT.surfaceAlt,
color: DT.textSecondary,
fontSize: { xs: 10, md: 11 },
fontWeight: 800,
letterSpacing: 0.6,
textTransform: 'uppercase',
whiteSpace: 'nowrap',
borderBottom: `1px solid ${DT.borderSubtle}`,
py: { xs: 1, md: 1.25 },
px: { xs: 1, md: 2 }
}
}}
>
<TableCell>#</TableCell>
<TableCell>Tenant</TableCell>
<TableCell>Zone</TableCell>
<TableCell>Slab</TableCell>
<TableCell align="center">Base Price</TableCell>
<TableCell align="center">Min KM</TableCell>
<TableCell align="center">Price / KM</TableCell>
<TableCell align="center">Max KM</TableCell>
<TableCell align="center">Min Orders</TableCell>
</TableRow>
</TableHead>
<TableBody>
{isLoading && <OrdersTableSkeleton col={5} />}
{rows.length === 0 && !isLoading ? (
<TableRow>
<TableCell colSpan={9} sx={{ py: 6 }}>
<Stack alignItems="center" spacing={1.5}>
<Avatar sx={{ width: 64, height: 64, bgcolor: soft('#94a3b8'), color: DT.textMuted }}>
<MdLocalOffer size={28} />
</Avatar>
<Typography variant="subtitle1" sx={{ fontWeight: 700, color: DT.textPrimary }}>
No pricing to show
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary }}>
{searchword ? 'Try a different keyword.' : 'Pick a zone above to load the catalog.'}
</Typography>
</Stack>
</TableCell>
</TableRow>
) : (
rows.map((row, index) => (
<TableRow
key={row.pricingid || `${row.appname}-${index}`}
sx={{
transition: 'background-color 0.15s',
'& td': {
borderBottom: `1px solid ${DT.divider}`,
py: { xs: 1, md: 1.5 },
px: { xs: 1, md: 2 }
},
'&:hover': { backgroundColor: DT.surfaceAlt }
}}
>
<TableCell>
<Typography variant="caption" sx={{ fontWeight: 700, color: DT.textMuted }}>
{String(index + 1).padStart(2, '0')}
</Typography>
</TableCell>
<TableCell>
<Stack direction="row" alignItems="center" spacing={1}>
<AccentAvatar color={BRAND} size={36}>
<MdGroups size={18} />
</AccentAvatar>
<Stack>
<Typography
variant="subtitle2"
sx={{ fontWeight: 700, color: DT.textPrimary, whiteSpace: 'nowrap' }}
>
{row.appname || '—'}
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary }}>
ID #{row.pricingid}
</Typography>
</Stack>
</Stack>
</TableCell>
<TableCell>
{row.applocation ? (
<CategoryChip icon={<MdPlace size={12} />} label={row.applocation} />
) : (
<Typography variant="caption" sx={{ color: DT.textMuted }}></Typography>
)}
</TableCell>
<TableCell>
<CategoryChip icon={<MdSpeed size={12} />} label={row.slab || '—'} />
</TableCell>
<TableCell align="center">
<MetricPill
color={BRAND}
icon={<MdPriceCheck size={12} />}
label={formatRupees(row.baseprice)}
width={110}
/>
</TableCell>
<TableCell align="center">
<MetricPill
color="#f59e0b"
icon={<MdStraighten size={12} />}
label={`${formatDecimal(row.minkm)} km`}
width={90}
/>
</TableCell>
<TableCell align="center">
<MetricPill
color="#10b981"
icon={<MdAttachMoney size={12} />}
label={formatRupees(row.priceperkm)}
width={110}
/>
</TableCell>
<TableCell align="center">
<MetricPill
color="#ef4444"
icon={<MdStraighten size={12} />}
label={`${formatDecimal(row.maxkm)} km`}
width={90}
/>
</TableCell>
<TableCell align="center">
<Stack direction="row" alignItems="center" justifyContent="center" spacing={0.5}>
<MdReceiptLong size={14} color={DT.textMuted} />
<Typography
variant="subtitle2"
sx={{ fontWeight: 700, color: DT.textPrimary, whiteSpace: 'nowrap' }}
>
{row.minorder ?? '—'}
</Typography>
</Stack>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</TableContainer>
)}
</Paper>
</>
);
};
export default ClientsPricing;

File diff suppressed because it is too large Load Diff

View File

@@ -11,13 +11,11 @@ import { MdPersonAddAlt1 } from 'react-icons/md';
// project import // project import
import MainCard from 'components/MainCard'; import MainCard from 'components/MainCard';
import axios from 'axios'; import axios from 'axios';
import { usePlacesWidget } from 'react-google-autocomplete'; import AddressAutocomplete, { geocodeAddress } from 'components/nearle_components/AddressAutocomplete';
import Loader from 'components/Loader'; import Loader from 'components/Loader';
import Geocode from 'react-geocode';
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import { DT, tint } from 'themes/dt/tokens'; import { DT, tint } from 'themes/dt/tokens';
// import { setLocationType } from 'react-geocode';
// const avatarImage = require.context('assets/images/users', true); // const avatarImage = require.context('assets/images/users', true);
@@ -51,9 +49,6 @@ const Createclient = () => {
const navigate = useNavigate(); const navigate = useNavigate();
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
// Geocode.setApiKey('AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8');
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
useEffect(() => { useEffect(() => {
@@ -65,25 +60,15 @@ const Createclient = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
try { let active = true;
Geocode.fromAddress(address).then( geocodeAddress(address).then((place) => {
(response) => { if (active && place) {
if (response.status == 'OK') { setLatlong({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() });
const { lat, lng } = response.results[0].geometry.location; }
setLatlong({
lat,
lng
}); });
console.log(response); return () => {
} active = false;
}, };
(error) => {
console.log(error);
}
);
} catch (err) {
console.log(err);
}
}, [address]); }, [address]);
const opentoast = (message) => { const opentoast = (message) => {
@@ -147,11 +132,7 @@ const Createclient = () => {
}); });
}; };
const { ref: materialRef } = usePlacesWidget({ const handleAddressPlaceSelected = (place) => {
apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
onPlaceSelected: (place) => {
console.log(place);
setAddress(place.formatted_address); setAddress(place.formatted_address);
let city1, zipcode1, state1, suburb1; let city1, zipcode1, state1, suburb1;
for (let i = 0; i < place.address_components.length; i++) { for (let i = 0; i < place.address_components.length; i++) {
@@ -167,6 +148,7 @@ const Createclient = () => {
zipcode1 = place.address_components[i].long_name; zipcode1 = place.address_components[i].long_name;
break; break;
case 'sublocality': case 'sublocality':
case 'sublocality_level_1':
suburb1 = place.address_components[i].long_name; suburb1 = place.address_components[i].long_name;
break; break;
} }
@@ -176,16 +158,7 @@ const Createclient = () => {
setState(state1 || ''); setState(state1 || '');
setZipcode(zipcode1 || ''); setZipcode(zipcode1 || '');
setSuburb(suburb1 || ''); setSuburb(suburb1 || '');
};
// setAddress(place.formatted_address)
},
// inputAutocompleteValue: "country",
options: {
// componentRestrictions: 'us',
// types: ["establishment"]
types: ['address' || 'geocode']
}
});
const createprofile = async () => { const createprofile = async () => {
console.log('res', businessname, businessno, mobilenumber, emailaddress, address, city, zipcode); console.log('res', businessname, businessno, mobilenumber, emailaddress, address, city, zipcode);
@@ -499,14 +472,13 @@ const Createclient = () => {
<Grid item xs={12}> <Grid item xs={12}>
<Stack spacing={1.25}> <Stack spacing={1.25}>
<InputLabel htmlFor="personal-address">Address</InputLabel> <InputLabel htmlFor="personal-address">Address</InputLabel>
<TextField <AddressAutocomplete
fullWidth
// defaultValue="Street 110-B Kalians Bag, Dewan, M.P. New York"
id="personal-address" id="personal-address"
fullWidth
placeholder="Address" placeholder="Address"
value={address} value={address}
onChange={(e) => setAddress(e.target.value)} onChange={setAddress}
inputRef={materialRef} onPlaceSelected={handleAddressPlaceSelected}
/> />
</Stack> </Stack>
</Grid> </Grid>

View File

@@ -47,7 +47,7 @@ import { TbMapPinCode } from 'react-icons/tb';
import { FaLocationDot } from 'react-icons/fa6'; import { FaLocationDot } from 'react-icons/fa6';
import axios from 'axios'; import axios from 'axios';
import { useTheme } from '@mui/material/styles'; import { useTheme } from '@mui/material/styles';
import Geocode from 'react-geocode'; import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete';
import Loader from 'components/Loader'; import Loader from 'components/Loader';
import * as geolib from 'geolib'; import * as geolib from 'geolib';
import MainCard from 'components/MainCard'; import MainCard from 'components/MainCard';
@@ -177,30 +177,14 @@ const SoftPaper = (props) => (
/> />
); );
function loadScript(src, position, id) {
if (!position) {
return;
}
const script = document.createElement('script');
script.setAttribute('async', '');
script.setAttribute('id', id);
script.src = src;
position.appendChild(script);
}
const Createorder1 = () => { const Createorder1 = () => {
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
// ================================================= || GoogleMaps (Drawer) || ================================================= // ================================================= || GoogleMaps (Drawer) || =================================================
const [value, setValue] = React.useState(null);
const [value1, setValue1] = React.useState(null);
const [inputValue, setInputValue] = React.useState(''); const [inputValue, setInputValue] = React.useState('');
const [inputValue1, setInputValue1] = React.useState(''); const [inputValue1, setInputValue1] = React.useState('');
const [inputValue2, setInputValue2] = React.useState(''); const [inputValue2, setInputValue2] = React.useState('');
const [inputValue3, setInputValue3] = React.useState(''); const [inputValue3, setInputValue3] = React.useState('');
const [options, setOptions] = React.useState([]); const [options, setOptions] = React.useState([]);
const [options1, setOptions1] = React.useState([]); const [options1, setOptions1] = React.useState([]);
const loaded = React.useRef(false);
const loaded1 = React.useRef(false); const loaded1 = React.useRef(false);
const [mobilenumber, setMobilenumber] = useState(''); const [mobilenumber, setMobilenumber] = useState('');
const [emailaddress, setEmailaddress] = useState(''); const [emailaddress, setEmailaddress] = useState('');
@@ -218,8 +202,6 @@ const Createorder1 = () => {
const [dropDoorno, setDropDoorno] = useState(''); const [dropDoorno, setDropDoorno] = useState('');
const [pickLandmark, setPickLandmark] = useState(''); const [pickLandmark, setPickLandmark] = useState('');
const [dropLandmark, setDropLandmark] = useState(''); const [dropLandmark, setDropLandmark] = useState('');
const [address, setAddress] = useState('');
const [address1, setAddress1] = useState('');
const [latlong, setLatlong] = useState({}); const [latlong, setLatlong] = useState({});
const [latlong1, setLatlong1] = useState({}); const [latlong1, setLatlong1] = useState({});
const autocompleteService = useRef(null); const autocompleteService = useRef(null);
@@ -252,225 +234,6 @@ const Createorder1 = () => {
{ label: '12 Angry Men', year: 1957 } { label: '12 Angry Men', year: 1957 }
]; ];
// // // ====================================================== || address (pick)|| ======================================================
// useEffect(() => {
// if (address) {
// try {
// Geocode.fromAddress(address).then(
// (response) => {
// if (response.status == 'OK') {
// const { lat, lng } = response.results[0].geometry.location;
// console.log({ lat, lng });
// setLatlong({
// lat,
// lng
// });
// console.log(response);
// if (response.results[0].address_components) {
// let place = response.results[0];
// let cityA, zipcodeA, stateA, suburbA;
// for (let i = 0; i < place.address_components.length; i++) {
// for (let j = 0; j < place.address_components[i].types.length; j++) {
// switch (place.address_components[i].types[j]) {
// case 'locality':
// cityA = place.address_components[i].long_name;
// break;
// case 'administrative_area_level_1':
// stateA = place.address_components[i].long_name;
// break;
// case 'postal_code':
// zipcodeA = place.address_components[i].long_name;
// break;
// case 'sublocality':
// suburbA = place.address_components[i].long_name;
// break;
// }
// }
// }
// setCity(cityA || '');
// setState(stateA || '');
// setZipcode(zipcodeA || '');
// setSuburb(suburbA || '');
// console.log({ lat, lng, cityA, stateA, zipcodeA, suburbA });
// setPickCust({
// ...pickCust
// // city: cityA,
// // state: stateA,
// // postcode: zipcodeA,
// // suburb: suburbA
// // latitude: lat,
// // longitude: lng
// });
// // setStartPoint({ latitude: lat, longitude: lng });
// }
// }
// },
// (error) => {
// console.log(error);
// }
// );
// } catch (err) {
// console.log(err);
// }
// }
// }, [address]);
// // // ====================================================== || address 1 (drop)|| ======================================================
// useEffect(() => {
// if (address) {
// try {
// Geocode.fromAddress(address1).then(
// (response) => {
// if (response.status == 'OK') {
// const { lat, lng } = response.results[0].geometry.location;
// setLatlong1({
// lat,
// lng
// });
// console.log(response);
// if (response.results[0].address_components) {
// let place = response.results[0];
// let cityB, zipcodeB, stateB, suburbB;
// for (let i = 0; i < place.address_components.length; i++) {
// for (let j = 0; j < place.address_components[i].types.length; j++) {
// switch (place.address_components[i].types[j]) {
// case 'locality':
// cityB = place.address_components[i].long_name;
// break;
// case 'administrative_area_level_1':
// stateB = place.address_components[i].long_name;
// break;
// case 'postal_code':
// zipcodeB = place.address_components[i].long_name;
// break;
// case 'sublocality':
// suburbB = place.address_components[i].long_name;
// break;
// }
// }
// }
// setCity(cityB || '');
// setState(stateB || '');
// setZipcode(zipcodeB || '');
// setSuburb(suburbB || '');
// console.log({ lat, lng, cityB, stateB, zipcodeB, suburbB });
// setDropCust({
// ...dropCust
// // city: cityB,
// // state: stateB,
// // postcode: zipcodeB,
// // suburb: suburbB
// // latitude: lat,
// // longitude: lng
// });
// // setEndPoint({ latitude: lat, longitude: lng });
// }
// }
// },
// (error) => {
// console.log(error);
// }
// );
// } catch (err) {
// console.log(err);
// }
// }
// }, [address1]);
if (typeof window !== 'undefined' && !loaded.current) {
if (!document.querySelector('#google-maps')) {
loadScript(
`https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLE_MAPS_API_KEY}&libraries=places&location=10.3656,77.9690&radius=50000&components=country:IN&strictbounds=true`,
document.querySelector('head'),
'google-maps'
);
}
loaded.current = true;
}
// const fetch = React.useMemo(
// () =>
// debounce((request, callback) => {
// autocompleteService.current.getPlacePredictions(request, callback);
// }, 400),
// []
// );
// const fetch1 = React.useMemo(
// () =>
// debounce((request, callback) => {
// autocompleteService.current.getPlacePredictions(request, callback);
// }, 400),
// []
// );
// ====================================================== || options (pick)|| ======================================================
// React.useEffect(() => {
// let active = true;
// if (!autocompleteService.current && window.google) {
// autocompleteService.current = new window.google.maps.places.AutocompleteService();
// }
// if (!autocompleteService.current) {
// return undefined;
// }
// if (inputValue === '') {
// setOptions(value ? [value] : []);
// return undefined;
// }
// fetch({ input: inputValue }, (results) => {
// if (active) {
// let newOptions = [];
// if (value) {
// newOptions = [value];
// }
// if (results) {
// newOptions = [...newOptions, ...results];
// }
// setOptions(newOptions);
// }
// });
// return () => {
// active = false;
// };
// }, [value, inputValue, fetch]);
// // ====================================================== || options1 (drop)|| ======================================================
// React.useEffect(() => {
// let active = true;
// if (!autocompleteService.current && window.google) {
// autocompleteService.current = new window.google.maps.places.AutocompleteService();
// }
// if (!autocompleteService.current) {
// return undefined;
// }
// if (inputValue1 === '') {
// setOptions1(value1 ? [value1] : []);
// return undefined;
// }
// fetch1({ input: inputValue1 }, (results) => {
// if (active) {
// let newOptions = [];
// if (value1) {
// newOptions = [value1];
// }
// if (results) {
// newOptions = [...newOptions, ...results];
// }
// setOptions1(newOptions);
// }
// });
// return () => {
// active = false;
// };
// }, [value1, inputValue1, fetch1]);
const appId = localStorage.getItem('applocationid'); const appId = localStorage.getItem('applocationid');
const navigate = useNavigate(); const navigate = useNavigate();
@@ -687,41 +450,6 @@ const Createorder1 = () => {
} }
}, [searchword]); }, [searchword]);
// const { ref: materialRef } = usePlacesWidget({
// apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
// onPlaceSelected: (place) => {
// console.log(place);
// // setAddress(place.formatted_address)
// let city1, zipcode1, state1, suburb1;
// for (let i = 0; i < place.address_components.length; i++) {
// for (let j = 0; j < place.address_components[i].types.length; j++) {
// switch (place.address_components[i].types[j]) {
// case 'locality':
// city1 = place.address_components[i].long_name;
// break;
// case 'administrative_area_level_1':
// state1 = place.address_components[i].long_name;
// break;
// case 'postal_code':
// zipcode1 = place.address_components[i].long_name;
// break;
// case 'sublocality':
// suburb1 = place.address_components[i].long_name;
// break;
// }
// }
// }
// // setCity(city1 || '')
// // setState(state1 || '');
// // setZipcode(zipcode1 || '');
// // setSuburb(suburb1 || '')
// },
// options: {
// types: ['address' || 'geocode']
// }
// });
// ==================================================== || fetchtenantinfo || ==================================================== // ==================================================== || fetchtenantinfo || ====================================================
const fetchtenantinfo = async () => { const fetchtenantinfo = async () => {
@@ -1161,32 +889,11 @@ const Createorder1 = () => {
setLoading(false); setLoading(false);
}); });
}; };
// ============================================= || Google Maps Autocomplete(pick) || ============================================= // ============================================= || Address Autocomplete (pick) || =============================================
useEffect(() => { const handlePickPlaceSelected = (place) => {
// Initialize Google Maps Autocomplete
if (inputValue2) {
const autocompleteInput = document.getElementById('addressAuto1');
const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, {
// types: ['(cities)'], // You can adjust the types parameter based on your requirements
strictBounds: true,
bounds: new window.google.maps.Circle({
// center: new window.google.maps.LatLng(11.0050707, 76.9509083),
// radius: 100000
center: new window.google.maps.LatLng(appLocaLat, appLocaLng),
radius: appLocaRadius * 1000
}).getBounds()
});
let arr = [];
// Event listener for autocomplete place changed
autocomplete.addListener('place_changed', () => {
const place = autocomplete.getPlace();
setInputValue2(`${place.name}, ${place.formatted_address}`); setInputValue2(`${place.name}, ${place.formatted_address}`);
console.log('new place', place); // Do something with the selected place
console.log(' pick (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place
// to trigger getDistance // to trigger getDistance
setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
setValue(place);
setAddress(`${place.name} ${place.formatted_address}`);
setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` }); setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` });
const address = { const address = {
address: `${place.name} ${place.formatted_address}`, address: `${place.name} ${place.formatted_address}`,
@@ -1242,36 +949,12 @@ const Createorder1 = () => {
latitude: place.geometry.location.lat(), latitude: place.geometry.location.lat(),
longitude: place.geometry.location.lng() longitude: place.geometry.location.lng()
}); });
console.log('Pick Address:', address); };
}); // ============================================= || Address Autocomplete (Drop) || =============================================
}
}, [inputValue2]);
// ============================================= || Google Maps Autocomplete(Drop) || =============================================
useEffect(() => { const handleDropPlaceSelected = (place) => {
if (inputValue3) {
// Initialize Google Maps Autocomplete
const autocompleteInput = document.getElementById('addressAuto2');
const autocomplete = new window.google.maps.places.Autocomplete(autocompleteInput, {
// types: ['(cities)'], // You can adjust the types parameter based on your requirements
strictBounds: true,
bounds: new window.google.maps.Circle({
// center: new window.google.maps.LatLng(11.0050707, 76.9509083),
center: new window.google.maps.LatLng(appLocaLat, appLocaLng),
radius: appLocaRadius * 1000 //km to m
// radius: 100000 //km to m
}).getBounds()
});
let arr = [];
// Event listener for autocomplete place changed
autocomplete.addListener('place_changed', () => {
const place = autocomplete.getPlace();
setInputValue3(`${place.name}, ${place.formatted_address}`); setInputValue3(`${place.name}, ${place.formatted_address}`);
console.log('new place', place); // Do something with the selected place
console.log('drop (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place
setEndPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() }); setEndPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
setValue1(place);
setAddress1(`${place.name} ${place.formatted_address}`);
setDropCust({ ...dropCust, address: `${place.name} ${place.formatted_address}` }); setDropCust({ ...dropCust, address: `${place.name} ${place.formatted_address}` });
const address = { const address = {
address: `${place.name} ${place.formatted_address}`, address: `${place.name} ${place.formatted_address}`,
@@ -1327,10 +1010,7 @@ const Createorder1 = () => {
latitude: place.geometry.location.lat(), latitude: place.geometry.location.lat(),
longitude: place.geometry.location.lng() longitude: place.geometry.location.lng()
}); });
console.log('Drop Address:', address); };
});
}
}, [inputValue3]);
// ============================================= || gettenantlocations (branches) || ============================================= // ============================================= || gettenantlocations (branches) || =============================================
const gettenantlocations = async () => { const gettenantlocations = async () => {
@@ -1609,15 +1289,18 @@ const Createorder1 = () => {
<Stack spacing={1.25} sx={{ mt: 0 }}> <Stack spacing={1.25} sx={{ mt: 0 }}>
{addId1 == 0 ? ( {addId1 == 0 ? (
<div> <div>
<TextField <AddressAutocomplete
variant="outlined"
label="Address" label="Address"
disabled={!isLocation} disabled={!isLocation}
id="addressAuto1" id="addressAuto1"
fullWidth fullWidth
value={inputValue2} value={inputValue2}
onChange={(e) => setInputValue2(e.target.value)} onChange={setInputValue2}
InputProps={{ onPlaceSelected={handlePickPlaceSelected}
bias={{ lat: appLocaLat, lng: appLocaLng }}
TextFieldProps={{
variant: 'outlined',
InputProps: {
endAdornment: ( endAdornment: (
<IconButton <IconButton
onClick={() => { onClick={() => {
@@ -1638,6 +1321,7 @@ const Createorder1 = () => {
<CloseIcon /> <CloseIcon />
</IconButton> </IconButton>
) )
}
}} }}
/> />
</div> </div>
@@ -2021,14 +1705,17 @@ const Createorder1 = () => {
<Stack spacing={1.25} sx={{ mt: 0 }}> <Stack spacing={1.25} sx={{ mt: 0 }}>
{addId2 == 0 ? ( {addId2 == 0 ? (
<div> <div>
<TextField <AddressAutocomplete
id="addressAuto2" id="addressAuto2"
disabled={!isLocation} disabled={!isLocation}
label="Address" label="Address"
fullWidth fullWidth
value={inputValue3} value={inputValue3}
onChange={(e) => setInputValue3(e.target.value)} onChange={setInputValue3}
InputProps={{ onPlaceSelected={handleDropPlaceSelected}
bias={{ lat: appLocaLat, lng: appLocaLng }}
TextFieldProps={{
InputProps: {
endAdornment: ( endAdornment: (
<IconButton <IconButton
onClick={() => { onClick={() => {
@@ -2049,6 +1736,7 @@ const Createorder1 = () => {
<CloseIcon /> <CloseIcon />
</IconButton> </IconButton>
) )
}
}} }}
/> />
</div> </div>

View File

@@ -1,157 +0,0 @@
/* eslint-disable no-unused-vars */
import * as React from 'react';
import Box from '@mui/material/Box';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';
import LocationOnIcon from '@mui/icons-material/LocationOn';
import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
import parse from 'autosuggest-highlight/parse';
import { debounce } from '@mui/material/utils';
// This key was created specifically for the demo in mui.com.
// You need to create a new one for your application.
const GOOGLE_MAPS_API_KEY ='AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8';
function loadScript(src, position, id) {
if (!position) {
return;
}
const script = document.createElement('script');
script.setAttribute('async', '');
script.setAttribute('id', id);
script.src = src;
position.appendChild(script);
}
const autocompleteService = { current: null };
export default function GoogleMaps() {
const [value, setValue] = React.useState(null);
const [inputValue, setInputValue] = React.useState('');
const [options, setOptions] = React.useState([]);
const loaded = React.useRef(false);
if (typeof window !== 'undefined' && !loaded.current) {
if (!document.querySelector('#google-maps')) {
loadScript(
`https://maps.googleapis.com/maps/api/js?key=${GOOGLE_MAPS_API_KEY}&libraries=places`,
document.querySelector('head'),
'google-maps',
);
}
loaded.current = true;
}
const fetch = React.useMemo(
() =>
debounce((request, callback) => {
autocompleteService.current.getPlacePredictions(request, callback);
}, 400),
[],
);
React.useEffect(() => {
let active = true;
if (!autocompleteService.current && window.google) {
autocompleteService.current =
new window.google.maps.places.AutocompleteService();
}
if (!autocompleteService.current) {
return undefined;
}
if (inputValue === '') {
setOptions(value ? [value] : []);
return undefined;
}
fetch({ input: inputValue }, (results) => {
if (active) {
let newOptions = [];
if (value) {
newOptions = [value];
}
if (results) {
newOptions = [...newOptions, ...results];
}
setOptions(newOptions);
}
});
return () => {
active = false;
};
}, [value, inputValue, fetch]);
return (
<Autocomplete
id="google-map-demo"
// sx={{ width: 300 }}
fullWidth
getOptionLabel={(option) =>
typeof option === 'string' ? option : option.description
}
filterOptions={(x) => x}
options={options}
autoComplete
includeInputInList
filterSelectedOptions
value={value}
noOptionsText="No locations"
onChange={(event, newValue) => {
setOptions(newValue ? [newValue, ...options] : options);
setValue(newValue);
}}
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue);
}}
renderInput={(params) => (
<TextField {...params}
// label="Add a location"
placeholder='Address'
fullWidth />
)}
renderOption={(props, option) => {
const matches =
option.structured_formatting.main_text_matched_substrings || [];
const parts = parse(
option.structured_formatting.main_text,
matches.map((match) => [match.offset, match.offset + match.length]),
);
return (
<li {...props}>
<Grid container alignItems="center">
<Grid item sx={{ display: 'flex', width: 44 }}>
<LocationOnIcon sx={{ color: 'text.secondary' }} />
</Grid>
<Grid item sx={{ width: 'calc(100% - 44px)', wordWrap: 'break-word' }}>
{parts.map((part, index) => (
<Box
key={index}
component="span"
sx={{ fontWeight: part.highlight ? 'bold' : 'regular' }}
>
{part.text}
</Box>
))}
<Typography variant="body2" color="text.secondary">
{option.structured_formatting.secondary_text}
</Typography>
</Grid>
</Grid>
</li>
);
}}
/>
);
}

View File

@@ -1,846 +0,0 @@
/* eslint-disable no-unused-vars */
import React from 'react';
import Loader from 'components/Loader';
import { useEffect, useState, Fragment } from 'react';
import { useTheme } from '@mui/material/styles';
import MainCard from 'components/MainCard';
import axios from 'axios';
import ClearIcon from '@mui/icons-material/Clear';
import { SearchOutlined, CloseOutlined } from '@ant-design/icons';
import { Empty } from 'antd';
import MyLocationIcon from '@mui/icons-material/MyLocation';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import dayjs from 'dayjs';
var utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
import { enqueueSnackbar } from 'notistack';
import { useNavigate } from 'react-router';
import { calculateDrivingDistance, calculateTotalCharge } from '../../../utils/distance';
import { GoogleMap, LoadScript, Marker } from '@react-google-maps/api';
import {
FormControl,
InputAdornment,
Grid,
Typography,
Stack,
Button,
TextField,
Autocomplete,
Divider,
Dialog,
DialogTitle,
DialogContent,
Checkbox,
DialogActions,
CircularProgress,
IconButton,
OutlinedInput,
FormGroup,
FormControlLabel,
Table,
TableContainer,
TableCell,
TableBody,
TableRow,
Paper,
TableHead,
Box
} from '@mui/material';
import CircularLoader from 'components/nearle_components/CircularLoader';
// import RidersPinPointOSM from './RidersPinPointOSM';
import RidersPinPoint from './ridersPinPoint';
const MultipleOrders = () => {
const navigate = useNavigate();
const theme = useTheme();
const [loading, setLoading] = useState(false);
const [btnLoading, setBtnLoading] = useState(false);
const [appId, setAppId] = useState(0);
const [tenantLocations, setTenantlocations] = useState([]);
const userid = localStorage.getItem('userid');
const tenId = localStorage.getItem('tenantid');
const [tid, setTid] = useState(0);
const [isLocation, setIsLocation] = useState(false);
const [basePrice, setBasePrice] = useState(0);
const [pricePerKm, setPricePerKm] = useState(0);
const [minKm, setMinKm] = useState(0);
const [pickCust, setPickCust] = useState(null);
const [dropCust, setDropCust] = useState([]);
const [isCustomerOpen, setIsCustomerOpen] = useState(false);
const [searchCustList, setSearchCustList] = useState('');
const [customerlist, setCustomerlist] = useState([]);
const [startdate, setStartdate] = useState(dayjs().format('MM-DD-YYYY'));
const [timeslotarr, setTimeslotarr] = useState([]);
const [starttime, setStatrttime] = useState();
const [endtime, setEndtime] = useState();
const [alertmessage, setAlertmessage] = useState('');
const [otherinstructions, setOtherinstructions] = useState('');
const [admintoken, setAdmintoken] = useState();
const [totaldist, settotaldist] = useState(0);
const [totalAmt, settotalAmt] = useState(0);
const [isLoading, setIsLoading] = useState(false);
const [showMap, setShowMap] = useState(false);
useEffect(() => {
dropCust && console.log('dropCust', dropCust);
}, [dropCust]);
// =============================================== || opentoast || ===============================================
const opentoast = (message, variant, time) => {
enqueueSnackbar(message, {
variant: variant,
anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: time ? time : 1500
});
console.log(alertmessage);
};
// ==============================|| fetchAppLocations ||============================== //
const fetchAppLocations = async () => {
try {
const locationRes = await axios.get(`${process.env.REACT_APP_URL}/partners/getlocations/?userid=${userid}`);
console.log('fetchAppLocations', locationRes.data.details);
} catch (err) {
console.log('locationRes', err);
}
};
useEffect(() => {
fetchAppLocations();
}, []);
// ============================================= || fetchTenantPricing || =============================================
const fetchTenantPricing = async (id) => {
try {
const pricingResponse = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantpricing/?tenantid=${tenId}`);
console.log('pricingResponse', pricingResponse.data.details);
setBasePrice(pricingResponse.data.details.baseprice);
setPricePerKm(pricingResponse.data.details.priceperkm);
setMinKm(pricingResponse.data.details.minkm);
} catch (error) {
console.log('fetchTenantPricing error', error);
}
};
useEffect(() => {
fetchTenantPricing();
}, []);
// ============================================= || gettenantlocations (branches) || =============================================
const gettenantlocations = async (id) => {
try {
const res = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantlocations/?tenantid=${id}`);
console.log('gettenantlocations', res.data.details);
if (res.data.details.length == 1) {
setIsLocation(true);
setTenantlocations(res.data.details);
setPickCust(res.data.details[0]);
} else {
setTenantlocations(res.data.details);
}
} catch (err) {
console.log('gettenantlocations', err);
}
};
useEffect(() => {
gettenantlocations(tenId);
}, []);
// ========================================================= || clientdetails || =========================================================
const clientdetails = async () => {
try {
let url =
searchCustList == ''
? `${process.env.REACT_APP_URL}/customers/gettenantcustomers/?tenantid=${tenId}&pageno=1&pagesize=10`
: `${process.env.REACT_APP_URL}/customers/search/?tenantid=${tenId}&keyword=${searchCustList}`;
await axios
.get(url)
.then((res) => {
if (res.data.status) {
console.log('clientdetails', res.data.details);
setCustomerlist(res.data.details);
let arr = [];
res.data.details.map((val) => {
arr.push({
label: `${val.firstname} | ${val.contactno}`,
...val
});
});
}
})
.catch((err) => {
console.log(err);
opentoast('server error', 'warning');
});
} catch (err) {
console.log(err);
}
};
useEffect(() => {
if (tenId) {
clientdetails();
}
}, [searchCustList.length > 3, searchCustList == '', tenId]);
// ========================================================= || calculateTotal(dist , charge) || =========================================================
const calculateTotal = () => {
let a1 = 0;
let a2 = 0;
dropCust?.map((customer) => {
a1 += customer.distance;
a2 += customer.totalcharge;
});
settotaldist(a1);
settotalAmt(a2);
};
useEffect(() => {
dropCust && calculateTotal();
}, [dropCust]);
// ========================================================= || handleCheckboxChange || =========================================================
const handleCheckboxChange = async (event, customer) => {
setIsLoading(true);
console.log('event', event.target.checked);
console.log('customer', customer);
if (event.target.checked) {
// If the checkbox is checked, calculate the distance and add the customer
try {
const obj = await calculateDistance(customer);
console.log('return of calculateDistance', obj);
const { roundedDistance, totalcharge } = obj;
// Create a new customer object with the distance property
const updatedCustomer = {
...customer,
distance: roundedDistance,
totalcharge: totalcharge
};
// Add the updated customer object to dropCust
setDropCust((prevDropCust) => [...prevDropCust, updatedCustomer]);
// Log the rounded distance
console.log(`Rounded Distance: ${roundedDistance} km`);
} catch (error) {
console.error('Failed to calculate distance:', error);
}
setIsLoading(false);
} else {
// If the checkbox is unchecked, remove the customer from dropCust
setDropCust((prevDropCust) => {
return prevDropCust.filter((cust) => cust.customerid !== customer.customerid);
});
setIsLoading(false);
}
};
// ========================================================= || calculateDistance || =========================================================
const calculateDistance = async (customer) => {
console.log('Distance calculation starts');
try {
const roundedDistance = await calculateDrivingDistance(pickCust, customer);
const totalcharge = calculateTotalCharge(roundedDistance, basePrice, pricePerKm, minKm);
return { roundedDistance, totalcharge };
} catch (error) {
console.error('Error calculating distance:', error);
throw error;
}
};
// ==================================================== || fetchTiming || ====================================================
const fetchTiming = async () => {
setLoading(true);
await axios
.get(`${process.env.REACT_APP_URL}/utils/getapplocations/?applocationid=${appId}`)
.then((res) => {
console.log('fetchTiming', res);
const { opentime, closetime, latitude, longitude, radius } = res.data.details[0];
if (res.data.status) {
setStatrttime(`${dayjs().format('MM-DD-YYYY')} ${opentime}`);
setEndtime(`${dayjs().format('MM-DD-YYYY')} ${closetime}`);
console.log('starttime', `${dayjs().format('MM-DD-YYYY')} ${opentime}`);
console.log('endtime', `${dayjs().format('MM-DD-YYYY')} ${closetime} `);
let arr = [];
for (
let i = `${dayjs().format('MM-DD-YYYY')} ${opentime}`, j = 0;
dayjs(`${dayjs().format('MM-DD-YYYY')} ${closetime} `).diff(i, 'm') >= 0;
j++, i = dayjs(i).add(30, 'm')
) {
arr.push(i);
}
console.log('setTimeslotarr', arr);
setTimeslotarr(arr);
}
setLoading(false);
})
.catch((err) => {
console.log(err);
setLoading(false);
});
};
useEffect(() => {
if (appId) {
fetchTiming();
}
}, [starttime, endtime, appId]);
const fetchAppAdminTokens = async () => {
setLoading(true);
await axios
.get(`${process.env.REACT_APP_URL}/utils/getapplocationconfig/?applocationid=${appId}`)
.then((res) => {
const userfcmtokemArray = res.data.details.applocationadmins.map((admin) => admin.userfcmtokem); // fcm => firebase cloud messaging
console.log('fetchAppAdminTokens', res);
console.log('userfcmtokemArray', userfcmtokemArray);
if (res.data.status) {
setAdmintoken(userfcmtokemArray);
}
setLoading(false);
})
.catch((err) => {
console.log(err);
setLoading(false);
});
};
useEffect(() => {
if (starttime && endtime) {
fetchAppAdminTokens();
}
}, [starttime, endtime]);
useEffect(() => {
console.log('pickCust', pickCust);
}, [pickCust]);
// ==================================================== || fetchtenantinfo || ====================================================
const fetchtenantinfo = async () => {
setLoading(true);
console.log('tid', tid);
await axios
.get(`${process.env.REACT_APP_URL}/tenants/gettenantinfo/?tenantid=${tid}`)
.then((res) => {
console.log('fetchtenantinfo', res);
if (res.data.status) {
fetchAppAdminTokens();
}
setLoading(false);
})
.catch((err) => {
console.log(err);
setLoading(false);
});
};
useEffect(() => {
if (tid) {
fetchtenantinfo();
}
}, [tid]);
// ================================================== || sendnotifications || ==================================================
const sendnotifications = async () => {
setLoading(true);
await axios
.post(`${process.env.REACT_APP_URL}/utils/sendnotifications`, {
priority: 'high',
registration_ids: admintoken,
data: {
accessid: process.env.REACT_APP_RIDER_ACCESS_ID
},
notification: {
title: 'Nearle Merchant',
body: 'An Order has been placed successfully,kindly process the same',
sound: 'ring'
}
})
.then((res) => {
console.log(res);
if (res.data.message == 'Success') {
enqueueSnackbar('Notification sent Successfully', {
variant: 'success',
anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 1000
});
}
setLoading(false);
})
.catch((err) => {
console.log(err);
enqueueSnackbar(err.message, {
variant: 'error',
anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 1000
});
setLoading(false);
});
};
// =============================================== || creategrouporders || ===============================================
const creategrouporders = async () => {
const arr = dropCust?.map((customer) => ({
applocationid: pickCust.applocationid,
cancellled: '',
// categoryid: +tenant.categoryid,
configid: 9,
customerid: customer.customerid,
deliveryaddress: customer.address || '',
deliverycharge: +customer.totalcharge || 0,
deliverycity: customer.city || '',
deliverycontactno: customer.contactno || '',
deliverycustomer: customer.firstname || '',
deliveryid: +customer.customerid,
deliverylandmark: customer.landmark || '',
deliverylat: customer.latitude,
deliverylocation: customer.suburb || '',
deliverylocationid: customer.deliverylocationid || 0,
deliverylong: customer.longitude,
// deliverytime: `${dayjs(startdate).format('YYYY-MM-DD HH:mm:ss')} `,
deliverytime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
deliverytype: 'B',
delivered: '',
itemcount: 1,
kms: customer.distance.toString() || 0,
locationid: +pickCust.locationid,
moduleid: +pickCust.moduleid,
orderamount: +customer.totalcharge || 0,
ordercharges: 0.0,
orderdate: dayjs().format('YYYY-MM-DD HH:mm:ss'),
orderheaderid: 0,
orderid: '', //
ordernotes: otherinstructions,
orderstatus: 'created',
ordervalue: +customer.totalcharge || 0,
partnerid: pickCust.partnerid,
partneruserid: +userid,
paymentstatus: 1,
paymenttype: 42,
pending: '',
pickupaddress: pickCust.address || '',
pickupcity: pickCust.locationcity || '',
pickupcontactno: pickCust.contactno || '',
pickupcustomer: pickCust.locationname || '',
pickuplandmark: pickCust.landmark || '',
pickuplat: pickCust.latitude,
pickuplocation: pickCust.suburb || '',
pickuplocationid: pickCust.locationid || 0,
pickuplong: pickCust.longitude,
processing: '',
ready: '',
remarks: '',
taxamount: 0.0,
tenantid: pickCust.tenantid,
tenantuserid: 0
}));
console.log('arr', arr);
if (!tenId) {
opentoast('Choose Client ', 'warning');
} else {
setLoading(true);
await axios
.post(`${process.env.REACT_APP_URL}/orders/createorders`, arr)
.then((res) => {
if (res.data.status) {
enqueueSnackbar('Order Created Successfully', {
variant: 'success',
anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 1000
});
if (admintoken) {
// notifyadmin(admintoken);
sendnotifications();
}
navigate('/nearle/orders');
} else {
opentoast(res.data.message, 'warning');
}
setLoading(false);
console.log(res);
})
.catch((err) => {
console.log(err);
// opentoast(err.data.message, 'warning');
setLoading(false);
});
}
console.log(arr);
};
return (
<>
{loading && <Loader />}
{/* <RidersPinPointOSM /> */}
<Grid container sx={{ mb: 2 }}>
<Grid item xs={12} sm={3} md={6}>
<Stack>
<Typography variant="h3" whiteSpace="nowrap">
Multiple Orders
</Typography>
</Stack>
</Grid>
<Grid item xs={12} sm={9} md={6}>
<Stack
sx={{}}
width={'100%'}
direction="row"
alignItems="center"
spacing={2}
justifyContent={'flex-end'}
flexWrap={{ xs: 'wrap', custom550: 'nowrap' }}
gap={2}
>
{/* Business Location */}
<Stack sx={{ width: '100%' }}>
{tenantLocations?.length === 1 ? (
<TextField
label="Business Location"
fullWidth
focused
value={tenantLocations[0]?.locationname}
InputProps={{
style: { color: theme.palette.primary.main },
startAdornment: (
<InputAdornment position="start">
<MyLocationIcon color="primary" />
</InputAdornment>
)
}}
/>
) : (
<Autocomplete
fullWidth
options={tenantLocations || []}
getOptionLabel={(option) => `${option.locationname} (${option.suburb})`}
onChange={(event, value, reason) => {
if (value) {
setTid(value.tenantid);
setIsLocation(true);
setPickCust(value);
}
if (reason === 'clear') setIsLocation(false);
}}
renderInput={(params) => <TextField {...params} label="Select Business Location" color="primary" fullWidth />}
/>
)}
</Stack>
{/* Date Picker */}
<Stack sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DatePicker
format="DD-MM-YYYY"
disablePast
value={dayjs(startdate)}
sx={{ width: 150 }}
onChange={(e) => {
let diff = dayjs().diff(dayjs(dayjs(e).format('YYYY-MM-DD')), 'd');
if (diff <= 0) {
setStartdate(e);
let arr = [];
timeslotarr.forEach((val) => {
if (dayjs().diff(dayjs(`${dayjs(e).format('MM-DD-YYYY')} ${dayjs(val).format('HH:mm:ss')}`), 'm') <= 0) {
arr.push(val);
}
});
if (arr[0]) {
setOrderarr([
{
sno: 1,
address: '',
customerid: '',
deliverytime: dayjs(arr[0]),
deliverylocationid: '',
clientname: '',
contactno: '',
latitude: '',
longitude: ''
}
]);
} else {
setOrderarr([]);
}
} else {
opentoast('choose Upcoming Date', 'warning');
setStartdate(NaN);
}
}}
/>
</LocalizationProvider>
</Stack>
</Stack>
</Grid>
</Grid>
{/* ===================================================== || Pickup || ===================================================== */}
{pickCust && (
<TableContainer component={Paper} sx={{ mb: 2 }}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Pickup Location</TableCell>
<TableCell>Address</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>{pickCust?.locationname}</TableCell>
<TableCell>{pickCust?.address}</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
)}
{/* ===================================================== || Drop || ===================================================== */}
<MainCard
sx={{ height: '100%' }}
title={`Drop (${dropCust?.length || 0})`}
secondary={
<Button
variant="outlined"
size="small"
sx={{
'&:hover': {
bgcolor: theme.palette.primary.main,
color: 'white'
}
}}
onClick={() => {
if (!isLocation) {
opentoast('Select Business Location', 'warning');
} else {
setIsCustomerOpen(true);
setSearchCustList('');
}
}}
>
Select Customers
</Button>
}
>
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>S.No</TableCell>
<TableCell>Customer</TableCell>
<TableCell>Address</TableCell>
<TableCell>Kms</TableCell>
<TableCell align="right">Charge</TableCell>
<TableCell>Action</TableCell>
</TableRow>
</TableHead>
<TableBody>
{!dropCust && (
<TableRow>
<TableCell colSpan={6}>
<Empty description={' Drop Customers Not Selected'} />
</TableCell>
</TableRow>
)}
{dropCust?.map((customer, index) => (
<TableRow key={index}>
<TableCell>{index + 1}</TableCell>
<TableCell>{customer.firstname}</TableCell>
<TableCell>{customer.address}</TableCell>
<TableCell>{customer.distance}</TableCell>
<TableCell align="right">{`${customer.totalcharge}.00`}</TableCell>
<TableCell align="center">
{
<CloseOutlined
style={{ cursor: 'pointer', color: 'red' }}
onClick={(event) => handleCheckboxChange(event, customer)}
/>
}
</TableCell>
</TableRow>
))}
{dropCust?.length != 0 && (
<TableRow>
<TableCell>
<Typography variant="h5">Total</Typography>
</TableCell>
<TableCell></TableCell>
<TableCell></TableCell>
<TableCell>
<Typography variant="h5">{`${totaldist} `}</Typography>
</TableCell>
<TableCell align="right">
<Typography variant="h5"> {`${totalAmt}.00`}</Typography>
</TableCell>
<TableCell></TableCell>
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
</MainCard>
{/* ================================================= || Riders Map || ================================================= */}
{/* {showMap && dropCust.length >= 1 && <RidersPinPoint pickCust={pickCust} dropCust={dropCust} />} */}
{/* ================================================= || Notes || ================================================= */}
{dropCust && (
<MainCard sx={{ mt: 2 }} title={'Notes'}>
<Grid container>
<Grid item xs={12}>
<TextField
focused
id="outlined-multiline-static"
sx={{ width: '100%', height: '100%', mb: 2 }}
multiline
rows={1}
placeholder="Notes"
value={otherinstructions}
onChange={(e) => setOtherinstructions(e.target.value)}
/>
</Grid>
<Stack direction="row" justifyContent={'end'} sx={{ mt: 2, width: '100%' }}>
<Button
disabled={dropCust?.length == 0}
size="medium"
variant="outlined"
onClick={() => {
setLoading(true);
setBtnLoading(true);
creategrouporders();
setTimeout(() => {
setLoading(false);
setBtnLoading(false);
}, 2000);
}}
sx={{
'&:hover': {
transform: 'scale(1.05)',
transition: 'transform 0.3s ease'
}
}}
>
{btnLoading ? <CircularProgress color="primary" size={20} thickness={10} /> : 'Create'}
</Button>
</Stack>
</Grid>
</MainCard>
)}
{/* ============================================= || saved address Dialog || ============================================= */}
<Dialog
open={isCustomerOpen}
onClose={() => {
setIsCustomerOpen(false);
}}
fullWidth
sx={{ minWidth: 'lg' }}
>
{isLoading && <CircularLoader />}
<DialogTitle sx={{ bgcolor: theme.palette.primary.main, color: 'white' }}>
<Stack>
<Typography variant="h4"> {`Select Drop Customers (${dropCust?.length || 0})`}</Typography>
<FormControl
sx={{
width: '100%',
mt: 1
}}
>
<Stack spacing={2} sx={{ py: 0.2 }}>
<OutlinedInput
fullWidth
id="input-search-header"
placeholder="Search"
value={searchCustList}
onChange={(e) => setSearchCustList(e.target.value)}
sx={{
'& .MuiOutlinedInput-input': {
p: '10.5px 0px 12px'
},
bgcolor: 'white'
}}
startAdornment={
<InputAdornment position="start">
<SearchOutlined style={{ fontSize: 'small' }} />
</InputAdornment>
}
endAdornment={
<IconButton
sx={{ visibility: searchCustList ? 'visible' : 'hidden' }}
onClick={() => {
setSearchCustList('');
}}
>
<ClearIcon />
</IconButton>
}
autoComplete="off"
/>
</Stack>
</FormControl>
</Stack>
</DialogTitle>
<Divider />
<DialogContent sx={{ p: 2.5 }}>
{customerlist.length == 0 ? (
<Stack spacing={2} direction={'row'} alignItems={'center'} justifyContent={'center'} sx={{ minHeight: 600, maxHeight: 600 }}>
<Empty />
</Stack>
) : (
<Stack spacing={2} sx={{ minHeight: 600, maxHeight: 600 }}>
{customerlist &&
customerlist.map((customer, index) => (
<FormGroup key={index}>
<FormControlLabel
control={
<Checkbox
checked={dropCust?.some((cust) => cust.customerid === customer.customerid)} // Set the checked state of the checkbox based on whether the customer is in `dropCust`
onChange={(event) => handleCheckboxChange(event, customer)}
/>
}
label={
<div style={{ width: '100%' }}>
<Typography variant="subtitle1" sx={{ textAlign: 'left' }}>
{`${customer.firstname} (${customer.contactno})`}
</Typography>
<Typography variant="body2" color="secondary" sx={{ textAlign: 'left' }}>
{customer.address}
</Typography>
</div>
}
/>
</FormGroup>
))}
</Stack>
)}
</DialogContent>
<Divider />
<DialogActions sx={{ p: 2.5 }}>
<Button
color={dropCust?.length !== 0 ? 'primary' : 'error'}
variant="outlined"
sx={{
'&:hover': {
bgcolor: dropCust?.length !== 0 ? theme.palette.primary.main : theme.palette.error.main,
color: 'white'
}
}}
onClick={() => {
setIsCustomerOpen(false);
{
dropCust?.length !== 0 && setShowMap(true);
}
}}
>
{dropCust?.length !== 0 ? 'Continue' : 'Close'}
</Button>
</DialogActions>
</Dialog>
</>
);
};
export default MultipleOrders;

File diff suppressed because it is too large Load Diff

View File

@@ -1,54 +0,0 @@
/* eslint-disable no-unused-vars */
import { LoadScriptNext, GoogleMap, Marker } from '@react-google-maps/api';
// distance function
function distance(lat1, lng1, lat2, lng2) {
const R = 6371;
const dLat = (lat2 - lat1) * (Math.PI / 180);
const dLng = (lng2 - lng1) * (Math.PI / 180);
const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) * Math.sin(dLng / 2) ** 2;
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
const containerStyle = {
width: '100%',
height: '300px'
};
export default function RidersPinPoint({ pickCust, dropCust }) {
// Ensure valid lat/lng
const center = pickCust?.latitude && pickCust?.longitude ? { lat: Number(pickCust.latitude), lng: Number(pickCust.longitude) } : null;
// If center missing, don't render map
if (!center) return null;
const sortedRiders = dropCust
?.map((r) => ({
...r,
distance: distance(center.lat, center.lng, Number(r.latitude), Number(r.longitude))
}))
.sort((a, b) => a.distance - b.distance);
return (
<LoadScriptNext googleMapsApiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY}>
<GoogleMap mapContainerStyle={containerStyle} zoom={11} center={center}>
<Marker position={center} icon={{ url: 'http://maps.google.com/mapfiles/ms/icons/purple-dot.png' }} />
{sortedRiders?.map((r, index) => (
<Marker
key={index}
position={{ lat: Number(r.latitude), lng: Number(r.longitude) }}
label={{
text: (index + 1).toString(),
color: 'white',
fontSize: '14px',
fontWeight: 'bold'
}}
/>
))}
</GoogleMap>
</LoadScriptNext>
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,94 +0,0 @@
import React, { useEffect, useRef } from 'react';
import { LoadScriptNext, GoogleMap } from '@react-google-maps/api';
import { DT } from 'themes/dt/tokens';
const containerStyle = {
width: '100%',
height: '90vh'
};
const MapWithRouteGoogle = ({ coordinates, additionalProps, setMapOpen }) => {
const mapRef = useRef(null);
/** Convert coordinates to numbers */
const numericCoordinates = coordinates
.map((c) => {
const lat = Number(c.lat);
const lng = Number(c.lng);
return isNaN(lat) || isNaN(lng) ? null : { lat, lng };
})
.filter(Boolean);
if (numericCoordinates.length < 2) {
return <div>No route data available</div>;
}
const start = numericCoordinates[0];
const end = numericCoordinates[numericCoordinates.length - 1];
/** Map loaded callback */
const onMapLoad = (map) => {
// draw markers
new window.google.maps.Marker({
position: start,
map,
label: 'S',
title: `Start: ${additionalProps?.riderStart}`
});
new window.google.maps.Marker({
position: end,
map,
label: 'E',
title: `End: ${additionalProps?.riderEnd}`
});
// draw rider route (point-to-point)
const route = new window.google.maps.Polyline({
path: numericCoordinates,
geodesic: false,
strokeColor: DT.brand,
strokeOpacity: 1.0,
strokeWeight: 4
});
route.setMap(map);
// auto fit
const bounds = new window.google.maps.LatLngBounds();
numericCoordinates.forEach((p) => bounds.extend(p));
map.fitBounds(bounds);
};
return (
<>
<button
onClick={() => setMapOpen(false)}
style={{
position: 'absolute',
top: 10,
right: 10,
zIndex: 999,
padding: '6px 12px',
background: DT.brand,
color: 'white',
borderRadius: DT.radiusInner,
cursor: 'pointer',
border: 'none',
fontWeight: 600,
boxShadow: DT.shadowMd
}}
>
Close
</button>
<LoadScriptNext googleMapsApiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY}>
<GoogleMap mapContainerStyle={containerStyle} center={start} zoom={14} onLoad={onMapLoad}>
{/* Polyline and markers added via onLoad */}
</GoogleMap>
</LoadScriptNext>
</>
);
};
export default MapWithRouteGoogle;

View File

@@ -1,10 +1,46 @@
import React, { useEffect, useMemo, useRef, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { GoogleMap, Polyline, Marker, InfoWindow, useJsApiLoader } from '@react-google-maps/api'; import { MapContainer, TileLayer, Polyline, Marker, Popup, useMap } from 'react-leaflet';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { Box, IconButton, Stack, Typography, CircularProgress } from '@mui/material'; import { Box, IconButton, Stack, Typography, CircularProgress } from '@mui/material';
import { MdClose, MdRoute } from 'react-icons/md'; import { MdClose, MdRoute } from 'react-icons/md';
const containerStyle = { width: '100%', height: '100%' }; const containerStyle = { width: '100%', height: '100%' };
// Numbered step icon — brand red to match the planned-route polyline below.
// Drawn fresh per render as a data URL so the step number can be baked into
// the SVG without juggling external marker assets.
const stepIcon = (n, isFocused) => {
const size = isFocused ? 38 : 32;
const color = isFocused ? '#910E1D' : '#C01227';
const svg = encodeURIComponent(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="${size}" height="${size}">` +
`<circle cx="16" cy="16" r="14" fill="${color}" stroke="white" stroke-width="3"/>` +
`<text x="16" y="21" text-anchor="middle" font-family="Arial,sans-serif" font-size="14" font-weight="700" fill="white">${n}</text>` +
`</svg>`
);
return new L.Icon({
iconUrl: `data:image/svg+xml;charset=UTF-8,${svg}`,
iconSize: [size, size],
iconAnchor: [size / 2, size / 2]
});
};
// Fits the map to the planned path once both the map and data are ready.
// Re-runs whenever the route changes (different rider / date).
const FitBoundsController = ({ dropPath }) => {
const map = useMap();
useEffect(() => {
if (!dropPath.length) return;
if (dropPath.length === 1) {
map.setView(dropPath[0], 14);
} else {
map.fitBounds(dropPath, { padding: [48, 48] });
}
}, [dropPath, map]);
return null;
};
// Renders a single rider's PLANNED route for the date range chosen on the // Renders a single rider's PLANNED route for the date range chosen on the
// Riders Summary page. `details` is an ordered array of waypoints (sorted by // Riders Summary page. `details` is an ordered array of waypoints (sorted by
// the planning step number) shaped as: // the planning step number) shaped as:
@@ -13,84 +49,38 @@ const containerStyle = { width: '100%', height: '100%' };
// `dropLat/dropLng` are required; pickup coords are optional and rendered as // `dropLat/dropLng` are required; pickup coords are optional and rendered as
// faded pre-stops if present. // faded pre-stops if present.
export default function RidersRoutes({ details, loading, riderName, dateRange, onClose }) { export default function RidersRoutes({ details, loading, riderName, dateRange, onClose }) {
const mapRef = useRef(null);
const [focusedStep, setFocusedStep] = useState(null); const [focusedStep, setFocusedStep] = useState(null);
const [routePath, setRoutePath] = useState([]); const [routePath, setRoutePath] = useState([]);
const [routeLoading, setRouteLoading] = useState(false); const [routeLoading, setRouteLoading] = useState(false);
const { isLoaded } = useJsApiLoader({
googleMapsApiKey: process.env.REACT_APP_GOOGLE_MAPS_KEY
});
// Step-pin coordinates in planning order — what the polyline connects. // Step-pin coordinates in planning order — what the polyline connects.
const dropPath = useMemo( const dropPath = useMemo(() => (details || []).map((d) => [d.dropLat, d.dropLng]), [details]);
() => (details || []).map((d) => ({ lat: d.dropLat, lng: d.dropLng })),
[details]
);
// Auto-fit map bounds to the full planned path once the map and data are
// both ready. Re-runs whenever the route changes (different rider / date).
useEffect(() => {
if (!isLoaded || !mapRef.current || dropPath.length === 0) return;
const bounds = new window.google.maps.LatLngBounds();
dropPath.forEach((p) => bounds.extend(p));
mapRef.current.fitBounds(bounds, 48);
}, [isLoaded, dropPath]);
// Resolve the rider's planned waypoints into an actual road-following path // Resolve the rider's planned waypoints into an actual road-following path
// via the Directions API. Without this, the polyline would cut across // via OSRM. Without this, the polyline would cut across buildings / aerial
// buildings / aerial lines — operators have no way to read the real route. // lines — operators have no way to read the real route.
// Directions has a 25-waypoint limit per request, so we chunk and stitch.
useEffect(() => { useEffect(() => {
if (!isLoaded || dropPath.length < 2) { if (dropPath.length < 2) {
setRoutePath([]); setRoutePath([]);
return; return;
} }
let cancelled = false; let cancelled = false;
const ds = new window.google.maps.DirectionsService();
const MAX_WPS = 23; // origin + 23 waypoints + destination = 25 stops/chunk
const fetchSegment = (origin, destination, waypoints) =>
new Promise((resolve, reject) => {
ds.route(
{
origin,
destination,
waypoints: waypoints.map((p) => ({ location: p, stopover: true })),
travelMode: window.google.maps.TravelMode.DRIVING
},
(result, status) => {
if (status === 'OK') resolve(result);
else reject(new Error(status));
}
);
});
(async () => { (async () => {
setRouteLoading(true); setRouteLoading(true);
try { try {
const points = dropPath; const coords = dropPath.map(([lat, lng]) => `${lng},${lat}`).join(';');
const all = []; const url = `https://router.project-osrm.org/route/v1/driving/${coords}?overview=full&geometries=geojson`;
let i = 0; const res = await fetch(url);
while (i < points.length - 1) { const data = await res.json();
const remaining = points.length - 1 - i; if (!cancelled && data.routes?.length) {
const take = Math.min(remaining, MAX_WPS + 1); const points = data.routes[0].geometry.coordinates.map(([lng, lat]) => [lat, lng]);
const origin = points[i]; setRoutePath(points);
const destination = points[i + take]; } else if (!cancelled) {
const waypoints = points.slice(i + 1, i + take); setRoutePath([]);
const res = await fetchSegment(origin, destination, waypoints);
const seg = res.routes[0].overview_path.map((ll) => ({
lat: ll.lat(),
lng: ll.lng()
}));
// Avoid duplicating the join point between adjacent chunks.
if (all.length > 0 && seg.length > 0) seg.shift();
all.push(...seg);
i += take;
} }
if (!cancelled) setRoutePath(all); } catch (e) {
} catch { console.warn('OSRM route error:', e);
// Fall back to the straight-line skeleton on failure (quota, no route, etc.).
if (!cancelled) setRoutePath([]); if (!cancelled) setRoutePath([]);
} finally { } finally {
if (!cancelled) setRouteLoading(false); if (!cancelled) setRouteLoading(false);
@@ -100,22 +90,7 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
return () => { return () => {
cancelled = true; cancelled = true;
}; };
}, [isLoaded, dropPath]); }, [dropPath]);
// Numbered step icon as a data URL — drawn fresh per render so we can pass
// the step number into the SVG without juggling external assets. Color is
// brand purple to match the planned-route polyline below.
const stepIcon = (n, isFocused) => {
const size = isFocused ? 38 : 32;
const color = isFocused ? '#910E1D' : '#C01227';
const svg = encodeURIComponent(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="${size}" height="${size}">` +
`<circle cx="16" cy="16" r="14" fill="${color}" stroke="white" stroke-width="3"/>` +
`<text x="16" y="21" text-anchor="middle" font-family="Arial,sans-serif" font-size="14" font-weight="700" fill="white">${n}</text>` +
`</svg>`
);
return `data:image/svg+xml;charset=UTF-8,${svg}`;
};
const headerBar = ( const headerBar = (
<Stack <Stack
@@ -133,12 +108,8 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
> >
<MdRoute size={20} /> <MdRoute size={20} />
<Stack sx={{ flex: 1, minWidth: 0 }}> <Stack sx={{ flex: 1, minWidth: 0 }}>
<Typography sx={{ fontWeight: 700, fontSize: 15, lineHeight: 1.2 }}> <Typography sx={{ fontWeight: 700, fontSize: 15, lineHeight: 1.2 }}>Planned route{riderName ? `${riderName}` : ''}</Typography>
Planned route{riderName ? `${riderName}` : ''} {dateRange && <Typography sx={{ fontSize: 12, opacity: 0.85 }}>{dateRange}</Typography>}
</Typography>
{dateRange && (
<Typography sx={{ fontSize: 12, opacity: 0.85 }}>{dateRange}</Typography>
)}
</Stack> </Stack>
{details && details.length > 0 && ( {details && details.length > 0 && (
<Typography sx={{ fontSize: 12, opacity: 0.9, fontWeight: 600 }}> <Typography sx={{ fontSize: 12, opacity: 0.9, fontWeight: 600 }}>
@@ -154,16 +125,14 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
</Stack> </Stack>
); );
// Loading state — route fetch in flight OR Google Maps script not ready yet. // Loading state — parent is still fetching the planned route data.
if (loading || !isLoaded) { if (loading) {
return ( return (
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}> <Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
{headerBar} {headerBar}
<Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1.5 }}> <Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1.5 }}>
<CircularProgress size={32} /> <CircularProgress size={32} />
<Typography sx={{ color: '#64748b', fontSize: 13 }}> <Typography sx={{ color: '#64748b', fontSize: 13 }}>Loading planned route</Typography>
{loading ? 'Loading planned route…' : 'Loading map…'}
</Typography>
</Stack> </Stack>
</Box> </Box>
); );
@@ -176,9 +145,7 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}> <Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
{headerBar} {headerBar}
<Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1, p: 3 }}> <Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1, p: 3 }}>
<Typography sx={{ color: '#1e293b', fontWeight: 700, fontSize: 16 }}> <Typography sx={{ color: '#1e293b', fontWeight: 700, fontSize: 16 }}>No planned route for this rider</Typography>
No planned route for this rider
</Typography>
<Typography sx={{ color: '#64748b', fontSize: 13, textAlign: 'center', maxWidth: 360 }}> <Typography sx={{ color: '#64748b', fontSize: 13, textAlign: 'center', maxWidth: 360 }}>
There are no deliveries with drop coordinates assigned to this rider for the selected date range. There are no deliveries with drop coordinates assigned to this rider for the selected date range.
</Typography> </Typography>
@@ -191,53 +158,21 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}> <Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
{headerBar} {headerBar}
<Box sx={{ flex: 1, minHeight: 0 }}> <Box sx={{ flex: 1, minHeight: 0 }}>
<GoogleMap <MapContainer center={dropPath[0]} zoom={14} style={containerStyle} zoomControl={false}>
mapContainerStyle={containerStyle} <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution="&copy; OpenStreetMap contributors" />
onLoad={(map) => (mapRef.current = map)} <FitBoundsController dropPath={dropPath} />
center={dropPath[0]}
zoom={14}
options={{
streetViewControl: false,
mapTypeControl: false,
fullscreenControl: false
}}
>
{routePath.length > 0 ? ( {routePath.length > 0 ? (
<> <>
{/* Translucent backdrop so the route stays legible on busy tiles. */} {/* Translucent backdrop so the route stays legible on busy tiles. */}
<Polyline <Polyline positions={routePath} pathOptions={{ color: '#C01227', opacity: 0.25, weight: 8 }} />
path={routePath} {/* Road-following planned route from OSRM. */}
options={{ strokeColor: '#C01227', strokeOpacity: 0.25, strokeWeight: 8 }} <Polyline positions={routePath} pathOptions={{ color: '#C01227', opacity: 0.95, weight: 4 }} />
/>
{/* Road-following planned route from the Directions API. */}
<Polyline
path={routePath}
options={{ strokeColor: '#C01227', strokeOpacity: 0.95, strokeWeight: 4 }}
/>
</> </>
) : ( ) : (
// Fallback while Directions is in flight (or if it fails) — dashed // Fallback while OSRM is in flight (or if it fails) — dashed
// straight-line skeleton between drop pins in step order. // straight-line skeleton between drop pins in step order.
<Polyline <Polyline positions={dropPath} pathOptions={{ color: '#C01227', opacity: 0.6, weight: 3, dashArray: '2 10', lineCap: 'round' }} />
path={dropPath}
options={{
strokeColor: '#C01227',
strokeOpacity: 0,
strokeWeight: 0,
icons: [
{
icon: {
path: 'M 0,-1 0,1',
strokeOpacity: 0.6,
strokeColor: '#C01227',
scale: 3
},
offset: '0',
repeat: '14px'
}
]
}}
/>
)} )}
{details.map((d, i) => { {details.map((d, i) => {
@@ -246,39 +181,29 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
return ( return (
<Marker <Marker
key={`step-${d.deliveryid || d.orderid || i}`} key={`step-${d.deliveryid || d.orderid || i}`}
position={{ lat: d.dropLat, lng: d.dropLng }} position={[d.dropLat, d.dropLng]}
icon={{ url: stepIcon(stepNum, isFocused) }} icon={stepIcon(stepNum, isFocused)}
onClick={() => setFocusedStep(isFocused ? null : d.deliveryid)} eventHandlers={{
zIndex={isFocused ? 1000 : stepNum} click: () => setFocusedStep(isFocused ? null : d.deliveryid)
}}
zIndexOffset={isFocused ? 1000 : stepNum}
> >
{isFocused && ( <Popup onClose={() => setFocusedStep(null)}>
<InfoWindow onCloseClick={() => setFocusedStep(null)}>
<Box sx={{ minWidth: 180, fontFamily: 'inherit' }}> <Box sx={{ minWidth: 180, fontFamily: 'inherit' }}>
<Typography sx={{ fontWeight: 800, fontSize: 13, color: '#0f172a' }}> <Typography sx={{ fontWeight: 800, fontSize: 13, color: '#0f172a' }}>
Step {stepNum} · {d.customer} Step {stepNum} · {d.customer}
</Typography> </Typography>
{d.address && ( {d.address && <Typography sx={{ fontSize: 12, color: '#475569', mt: 0.5 }}>{d.address}</Typography>}
<Typography sx={{ fontSize: 12, color: '#475569', mt: 0.5 }}>
{d.address}
</Typography>
)}
{d.expectedTime && ( {d.expectedTime && (
<Typography sx={{ fontSize: 12, color: '#64748b', mt: 0.5 }}> <Typography sx={{ fontSize: 12, color: '#64748b', mt: 0.5 }}>ETA {String(d.expectedTime).slice(11, 16) || d.expectedTime}</Typography>
ETA {String(d.expectedTime).slice(11, 16) || d.expectedTime}
</Typography>
)}
{d.orderid && (
<Typography sx={{ fontSize: 11, color: '#94a3b8', mt: 0.5 }}>
Order #{d.orderid}
</Typography>
)} )}
{d.orderid && <Typography sx={{ fontSize: 11, color: '#94a3b8', mt: 0.5 }}>Order #{d.orderid}</Typography>}
</Box> </Box>
</InfoWindow> </Popup>
)}
</Marker> </Marker>
); );
})} })}
</GoogleMap> </MapContainer>
</Box> </Box>
</Box> </Box>
); );

View File

@@ -53,7 +53,7 @@ import { useState, useEffect } from 'react';
import axios from 'axios'; import axios from 'axios';
import Loader from 'components/Loader'; import Loader from 'components/Loader';
import Transitions from 'components/@extended/Transitions'; import Transitions from 'components/@extended/Transitions';
import Autocomplete from 'react-google-autocomplete'; import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete';
import * as React from 'react'; import * as React from 'react';
@@ -63,8 +63,6 @@ import TablePagination from '@mui/material/TablePagination';
import TableSortLabel from '@mui/material/TableSortLabel'; import TableSortLabel from '@mui/material/TableSortLabel';
import { visuallyHidden } from '@mui/utils'; import { visuallyHidden } from '@mui/utils';
import Geocode from 'react-geocode';
const Requests = () => { const Requests = () => {
// let dispatch = useDispatch(); // let dispatch = useDispatch();
@@ -204,7 +202,6 @@ const Requests = () => {
const [suburb, setSuburb] = useState(''); const [suburb, setSuburb] = useState('');
const [currenttenantid] = useState(''); const [currenttenantid] = useState('');
const [latlong, setLatlong] = useState({}); const [latlong, setLatlong] = useState({});
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
const [alertmessage, setAlertmessage] = useState(''); const [alertmessage, setAlertmessage] = useState('');
// const [toast, setToast] = useState(false); // const [toast, setToast] = useState(false);
const [rolesarr, setRolesarr] = useState([]); const [rolesarr, setRolesarr] = useState([]);
@@ -286,27 +283,34 @@ const Requests = () => {
// } // }
useEffect(() => { const handleAddressPlaceSelected = (place) => {
try { setAddress(place.formatted_address);
Geocode.fromAddress(address).then( setLatlong({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() });
(response) => { let city1, state, zipcode1, suburb1;
if (response.status == 'OK') { place.address_components.forEach((component) => {
const { lat, lng } = response.results[0].geometry.location; component.types.forEach((type) => {
setLatlong({ switch (type) {
lat, case 'locality':
lng city1 = component.long_name;
break;
case 'administrative_area_level_1':
state = component.long_name;
break;
case 'postal_code':
zipcode1 = component.long_name;
break;
case 'sublocality':
case 'sublocality_level_1':
suburb1 = component.long_name;
break;
}
}); });
console.log(response); });
} setCity(city1 || '');
}, setState1(state || '');
(error) => { setZipcode(zipcode1 || '');
console.log(error); setSuburb(suburb1 || '');
} };
);
} catch (err) {
console.log(err);
}
}, [address]);
useEffect(() => { useEffect(() => {
console.log('rolesarr'); console.log('rolesarr');
@@ -1467,53 +1471,22 @@ const Requests = () => {
{/* } */} {/* } */}
<Autocomplete <AddressAutocomplete
className="automap" id="request-address-autocomplete"
apiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY} fullWidth
style={{
width: '100%',
height: '40px',
borderRadius: '5px',
border: '1px solid #e0e0e0',
textIndent: '10px',
outline: 'none'
// ':hover': {
// border: '1px solid #00b0ff !important',
// backgroundColor:'blue'
// }
}}
onPlaceSelected={(place) => {
setAddress(place.formatted_address);
let city1, state, zipcode1, suburb1;
for (let i = 0; i < place.address_components.length; i++) {
for (let j = 0; j < place.address_components[i].types.length; j++) {
switch (place.address_components[i].types[j]) {
case 'locality':
city1 = place.address_components[i].long_name;
break;
case 'administrative_area_level_1':
state = place.address_components[i].long_name;
break;
case 'postal_code':
zipcode1 = place.address_components[i].long_name;
break;
case 'sublocality':
suburb1 = place.address_components[i].long_name;
break;
}
}
}
setCity(city1 || '');
setState1(state || '');
setZipcode(zipcode1 || '');
setSuburb(suburb1 || '');
}}
options={{
types: ['address' || 'geocode']
}}
placeholder="Address" placeholder="Address"
value={address} value={address}
onChange={(e) => setAddress(e.target.value)} onChange={setAddress}
onPlaceSelected={handleAddressPlaceSelected}
TextFieldProps={{
className: 'automap',
InputProps: {
style: {
borderRadius: '5px',
border: '1px solid #e0e0e0'
}
}
}}
/> />
</Stack> </Stack>
</Grid> </Grid>

View File

@@ -13,12 +13,10 @@ import { DT, tint } from 'themes/dt/tokens';
import MainCard from 'components/MainCard'; import MainCard from 'components/MainCard';
import axios from 'axios'; import axios from 'axios';
// assets // assets
import { usePlacesWidget } from 'react-google-autocomplete'; import AddressAutocomplete, { geocodeAddress } from 'components/nearle_components/AddressAutocomplete';
import Loader from 'components/Loader'; import Loader from 'components/Loader';
import Geocode from 'react-geocode';
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
// import { setLocationType } from 'react-geocode';
// const avatarImage = require.context('assets/images/users', true); // const avatarImage = require.context('assets/images/users', true);
@@ -52,9 +50,6 @@ const Createrider = () => {
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md')); const isMobile = useMediaQuery(theme.breakpoints.down('md'));
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
// Geocode.setApiKey('AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8');
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
useEffect(() => { useEffect(() => {
@@ -66,25 +61,15 @@ const Createrider = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
try { let active = true;
Geocode.fromAddress(address).then( geocodeAddress(address).then((place) => {
(response) => { if (active && place) {
if (response.status == 'OK') { setLatlong({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() });
const { lat, lng } = response.results[0].geometry.location; }
setLatlong({
lat,
lng
}); });
console.log(response); return () => {
} active = false;
}, };
(error) => {
console.log(error);
}
);
} catch (err) {
console.log(err);
}
}, [address]); }, [address]);
const opentoast = (message) => { const opentoast = (message) => {
@@ -115,11 +100,7 @@ const Createrider = () => {
}); });
}; };
const { ref: materialRef } = usePlacesWidget({ const handleAddressPlaceSelected = (place) => {
apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
onPlaceSelected: (place) => {
console.log(place);
setAddress(place.formatted_address); setAddress(place.formatted_address);
let city1, zipcode1, state1, suburb1; let city1, zipcode1, state1, suburb1;
for (let i = 0; i < place.address_components.length; i++) { for (let i = 0; i < place.address_components.length; i++) {
@@ -135,6 +116,7 @@ const Createrider = () => {
zipcode1 = place.address_components[i].long_name; zipcode1 = place.address_components[i].long_name;
break; break;
case 'sublocality': case 'sublocality':
case 'sublocality_level_1':
suburb1 = place.address_components[i].long_name; suburb1 = place.address_components[i].long_name;
break; break;
} }
@@ -144,16 +126,7 @@ const Createrider = () => {
setState(state1 || ''); setState(state1 || '');
setZipcode(zipcode1 || ''); setZipcode(zipcode1 || '');
setSuburb(suburb1 || ''); setSuburb(suburb1 || '');
};
// setAddress(place.formatted_address)
},
// inputAutocompleteValue: "country",
options: {
// componentRestrictions: 'us',
// types: ["establishment"]
types: ['address' || 'geocode']
}
});
const createprofile = async () => { const createprofile = async () => {
if (!firstname) { if (!firstname) {
@@ -339,14 +312,13 @@ const Createrider = () => {
<Grid item xs={12}> <Grid item xs={12}>
<Stack spacing={1.25}> <Stack spacing={1.25}>
<InputLabel htmlFor="personal-address">Address</InputLabel> <InputLabel htmlFor="personal-address">Address</InputLabel>
<TextField <AddressAutocomplete
fullWidth
// defaultValue="Street 110-B Kalians Bag, Dewan, M.P. New York"
id="personal-address" id="personal-address"
fullWidth
placeholder="Address" placeholder="Address"
value={address} value={address}
onChange={(e) => setAddress(e.target.value)} onChange={setAddress}
inputRef={materialRef} onPlaceSelected={handleAddressPlaceSelected}
/> />
</Stack> </Stack>
</Grid> </Grid>

View File

@@ -31,9 +31,8 @@ import { DatePicker } from '@mui/x-date-pickers/DatePicker';
// project import // project import
import MainCard from 'components/MainCard'; import MainCard from 'components/MainCard';
import axios from 'axios'; import axios from 'axios';
import { usePlacesWidget } from 'react-google-autocomplete'; import AddressAutocomplete from 'components/nearle_components/AddressAutocomplete';
import Loader from 'components/Loader'; import Loader from 'components/Loader';
import Geocode from 'react-geocode';
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import CircularLoader from 'components/CircularLoader'; import CircularLoader from 'components/CircularLoader';
@@ -58,8 +57,6 @@ const EditRider = () => {
const [locaName, setLocoName] = useState(); const [locaName, setLocoName] = useState();
const userid = localStorage.getItem('userid'); const userid = localStorage.getItem('userid');
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const fetchRiderData = async (id) => { const fetchRiderData = async (id) => {
@@ -231,13 +228,10 @@ const EditRider = () => {
}); });
}; };
const { ref: materialRef } = usePlacesWidget({ const handleAddressPlaceSelected = (place) => {
apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
onPlaceSelected: (place) => {
console.log(place);
setAddress(place.formatted_address); setAddress(place.formatted_address);
let city1, zipcode1, state1, suburb1; let city1, state1, suburb1;
for (let i = 0; i < place.address_components.length; i++) { for (let i = 0; i < place.address_components.length; i++) {
for (let j = 0; j < place.address_components[i].types.length; j++) { for (let j = 0; j < place.address_components[i].types.length; j++) {
switch (place.address_components[i].types[j]) { switch (place.address_components[i].types[j]) {
@@ -247,29 +241,17 @@ const EditRider = () => {
case 'administrative_area_level_1': case 'administrative_area_level_1':
state1 = place.address_components[i].long_name; state1 = place.address_components[i].long_name;
break; break;
case 'postal_code':
zipcode1 = place.address_components[i].long_name;
break;
case 'sublocality': case 'sublocality':
case 'sublocality_level_1':
suburb1 = place.address_components[i].long_name; suburb1 = place.address_components[i].long_name;
break; break;
} }
} }
} }
setCity(city1 || ''); setCity(city1 || '');
setState(state1 || ''); setState(state1 || '');
setSuburb(suburb1 || ''); setSuburb(suburb1 || '');
};
// setAddress(place.formatted_address)
},
// inputAutocompleteValue: "country",
options: {
// componentRestrictions: 'us',
// types: ["establishment"]
types: ['address' || 'geocode']
}
});
const updateRider = async () => { const updateRider = async () => {
setLoading(true); setLoading(true);
@@ -487,16 +469,13 @@ const EditRider = () => {
<Grid item xs={12}> <Grid item xs={12}>
<Stack spacing={1.25}> <Stack spacing={1.25}>
<InputLabel htmlFor="personal-address">Address</InputLabel> <InputLabel htmlFor="personal-address">Address</InputLabel>
<TextField <AddressAutocomplete
fullWidth
// defaultValue="Street 110-B Kalians Bag, Dewan, M.P. New York"
id="personal-address" id="personal-address"
fullWidth
placeholder="Address" placeholder="Address"
value={address} value={address}
onChange={(e) => { onChange={setAddress}
setAddress(e.target.value); onPlaceSelected={handleAddressPlaceSelected}
}}
inputRef={materialRef}
/> />
</Stack> </Stack>
</Grid> </Grid>

View File

@@ -1,6 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import { useState, useEffect, useRef, Fragment } from 'react'; import { useState, useEffect, useRef, Fragment } from 'react';
import Geocode from 'react-geocode';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import axios from 'axios'; import axios from 'axios';
import { import {
@@ -491,8 +490,6 @@ const Riders = () => {
} }
}); });
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
const handleChangetab = (i) => { const handleChangetab = (i) => {
setTabvalue(i); setTabvalue(i);
setLogsRow(null); setLogsRow(null);

View File

@@ -22,6 +22,9 @@ const OrdersPreview = Loadable(lazy(() => import('pages/nearle/orders/OrdersPrev
const Deliveries = Loadable(lazy(() => import('pages/nearle/deliveries/deliveries'))); const Deliveries = Loadable(lazy(() => import('pages/nearle/deliveries/deliveries')));
const Tenants = Loadable(lazy(() => import('pages/nearle/clients/Tenants')));
const ClientsPricing = Loadable(lazy(() => import('pages/nearle/clientPricing/clientPricing')));
const Details = Loadable(lazy(() => import('pages/nearle/orders/details'))); const Details = Loadable(lazy(() => import('pages/nearle/orders/details')));
const ViewProfile = Loadable(lazy(() => import('pages/nearle/viewProfile'))); const ViewProfile = Loadable(lazy(() => import('pages/nearle/viewProfile')));
@@ -70,6 +73,14 @@ const MainRoutes = {
path: 'deliveries', path: 'deliveries',
element: <Deliveries /> element: <Deliveries />
}, },
{
path: 'tenants',
element: <Tenants />
},
{
path: 'pricing',
element: <ClientsPricing />
},
{ {
path: 'requests', path: 'requests',
element: <Requests /> element: <Requests />

View File

@@ -8,6 +8,8 @@
"orderspreview": "Orders Preview", "orderspreview": "Orders Preview",
"deliveries": "Deliveries", "deliveries": "Deliveries",
"riders": "Riders", "riders": "Riders",
"tenants": "Tenants",
"pricing": "Pricing",
"reports": "Reports", "reports": "Reports",
"ordersummary": "Orders Summary", "ordersummary": "Orders Summary",
"ordersdetails": "Orders Details", "ordersdetails": "Orders Details",

213
yarn.lock
View File

@@ -79,7 +79,7 @@
jsonpointer "^5.0.0" jsonpointer "^5.0.0"
leven "^3.1.0" leven "^3.1.0"
"@astryxdesign/core@^0.1.9", "@astryxdesign/core@0.1.9": "@astryxdesign/core@^0.1.9":
version "0.1.9" version "0.1.9"
resolved "https://registry.npmjs.org/@astryxdesign/core/-/core-0.1.9.tgz" resolved "https://registry.npmjs.org/@astryxdesign/core/-/core-0.1.9.tgz"
integrity sha512-2ZNypZFfujMPxdU8M9Jbe77vwFPP1FYvA0Pk/3L3OLxEIzi98qLbRJjhDEHLbrflANSFVB4l5+qYpJjYtFFXMQ== integrity sha512-2ZNypZFfujMPxdU8M9Jbe77vwFPP1FYvA0Pk/3L3OLxEIzi98qLbRJjhDEHLbrflANSFVB4l5+qYpJjYtFFXMQ==
@@ -107,7 +107,7 @@
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz" resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz"
integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg== integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.0.0-0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.12.0", "@babel/core@^7.12.3", "@babel/core@^7.13.0", "@babel/core@^7.16.0", "@babel/core@^7.21.3", "@babel/core@^7.21.4", "@babel/core@^7.4.0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.4.0-0", "@babel/core@^7.7.2", "@babel/core@^7.8.0", "@babel/core@>=7.11.0": "@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.12.3", "@babel/core@^7.16.0", "@babel/core@^7.21.3", "@babel/core@^7.21.4", "@babel/core@^7.7.2", "@babel/core@^7.8.0":
version "7.29.7" version "7.29.7"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz" resolved "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz"
integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA== integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==
@@ -467,7 +467,7 @@
dependencies: dependencies:
"@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-syntax-flow@^7.14.5", "@babel/plugin-syntax-flow@^7.16.7": "@babel/plugin-syntax-flow@^7.16.7":
version "7.26.0" version "7.26.0"
resolved "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz" resolved "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz"
integrity sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg== integrity sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==
@@ -917,7 +917,7 @@
dependencies: dependencies:
"@babel/plugin-transform-react-jsx" "^7.27.1" "@babel/plugin-transform-react-jsx" "^7.27.1"
"@babel/plugin-transform-react-jsx@^7.14.9", "@babel/plugin-transform-react-jsx@^7.27.1": "@babel/plugin-transform-react-jsx@^7.27.1":
version "7.27.1" version "7.27.1"
resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz" resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz"
integrity sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw== integrity sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==
@@ -1346,7 +1346,7 @@
resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz" resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz"
integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==
"@emotion/is-prop-valid@*", "@emotion/is-prop-valid@^1.2.0": "@emotion/is-prop-valid@^1.2.0":
version "1.2.0" version "1.2.0"
resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz" resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz"
integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg== integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==
@@ -1363,7 +1363,7 @@
resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz" resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz"
integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==
"@emotion/react@^11.0.0-rc.0", "@emotion/react@^11.10.6", "@emotion/react@^11.4.1", "@emotion/react@^11.5.0", "@emotion/react@^11.9.0": "@emotion/react@^11.10.6":
version "11.10.6" version "11.10.6"
resolved "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz" resolved "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz"
integrity sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw== integrity sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==
@@ -1393,7 +1393,7 @@
resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz" resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz"
integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==
"@emotion/styled@^11.10.6", "@emotion/styled@^11.3.0", "@emotion/styled@^11.8.1": "@emotion/styled@^11.10.6":
version "11.10.6" version "11.10.6"
resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz" resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz"
integrity sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og== integrity sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==
@@ -1526,7 +1526,7 @@
"@firebase/util" "1.10.0" "@firebase/util" "1.10.0"
tslib "^2.1.0" tslib "^2.1.0"
"@firebase/app-compat@0.2.43", "@firebase/app-compat@0.x": "@firebase/app-compat@0.2.43":
version "0.2.43" version "0.2.43"
resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.43.tgz" resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.43.tgz"
integrity sha512-HM96ZyIblXjAC7TzE8wIk2QhHlSvksYkQ4Ukh1GmEenzkucSNUmUX4QvoKrqeWsLEQ8hdcojABeCV8ybVyZmeg== integrity sha512-HM96ZyIblXjAC7TzE8wIk2QhHlSvksYkQ4Ukh1GmEenzkucSNUmUX4QvoKrqeWsLEQ8hdcojABeCV8ybVyZmeg==
@@ -1537,12 +1537,12 @@
"@firebase/util" "1.10.0" "@firebase/util" "1.10.0"
tslib "^2.1.0" tslib "^2.1.0"
"@firebase/app-types@0.9.2", "@firebase/app-types@0.x": "@firebase/app-types@0.9.2":
version "0.9.2" version "0.9.2"
resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.2.tgz" resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.2.tgz"
integrity sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ== integrity sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ==
"@firebase/app@0.10.13", "@firebase/app@0.x": "@firebase/app@0.10.13":
version "0.10.13" version "0.10.13"
resolved "https://registry.npmjs.org/@firebase/app/-/app-0.10.13.tgz" resolved "https://registry.npmjs.org/@firebase/app/-/app-0.10.13.tgz"
integrity sha512-OZiDAEK/lDB6xy/XzYAyJJkaDqmQ+BCtOEPLqFvxWKUz5JbBmej7IiiRHdtiIOD/twW7O5AxVsfaaGA/V1bNsA== integrity sha512-OZiDAEK/lDB6xy/XzYAyJJkaDqmQ+BCtOEPLqFvxWKUz5JbBmej7IiiRHdtiIOD/twW7O5AxVsfaaGA/V1bNsA==
@@ -1839,7 +1839,7 @@
tslib "^2.1.0" tslib "^2.1.0"
undici "6.19.7" undici "6.19.7"
"@firebase/util@1.10.0", "@firebase/util@1.x": "@firebase/util@1.10.0":
version "1.10.0" version "1.10.0"
resolved "https://registry.npmjs.org/@firebase/util/-/util-1.10.0.tgz" resolved "https://registry.npmjs.org/@firebase/util/-/util-1.10.0.tgz"
integrity sha512-xKtx4A668icQqoANRxyDLBLz51TAbDP9KRfpbKGxiCAW346d0BeJe5vN6/hKxxmWwnZ0mautyv39JxviwwQMOQ== integrity sha512-xKtx4A668icQqoANRxyDLBLz51TAbDP9KRfpbKGxiCAW346d0BeJe5vN6/hKxxmWwnZ0mautyv39JxviwwQMOQ==
@@ -1958,19 +1958,6 @@
intl-messageformat "10.7.18" intl-messageformat "10.7.18"
tslib "^2.8.0" tslib "^2.8.0"
"@googlemaps/js-api-loader@1.16.8":
version "1.16.8"
resolved "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.16.8.tgz"
integrity sha512-CROqqwfKotdO6EBjZO/gQGVTbeDps5V7Mt9+8+5Q+jTg5CRMi3Ii/L9PmV3USROrt2uWxtGzJHORmByxyo9pSQ==
"@googlemaps/markerclusterer@2.5.3":
version "2.5.3"
resolved "https://registry.npmjs.org/@googlemaps/markerclusterer/-/markerclusterer-2.5.3.tgz"
integrity sha512-x7lX0R5yYOoiNectr10wLgCBasNcXFHiADIBdmn7jQllF2B5ENQw5XtZK+hIw4xnV0Df0xhN4LN98XqA5jaiOw==
dependencies:
fast-deep-equal "^3.1.3"
supercluster "^8.0.1"
"@grpc/grpc-js@~1.9.0": "@grpc/grpc-js@~1.9.0":
version "1.9.14" version "1.9.14"
resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz" resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz"
@@ -2344,7 +2331,7 @@
clsx "^2.1.0" clsx "^2.1.0"
prop-types "^15.8.1" prop-types "^15.8.1"
"@mui/material@^5.0.0", "@mui/material@^5.12.1", "@mui/material@^5.15.14 || ^6.0.0 || ^7.0.0", "@mui/material@>=5.15.0": "@mui/material@^5.12.1":
version "5.16.14" version "5.16.14"
resolved "https://registry.npmjs.org/@mui/material/-/material-5.16.14.tgz" resolved "https://registry.npmjs.org/@mui/material/-/material-5.16.14.tgz"
integrity sha512-eSXQVCMKU2xc7EcTxe/X/rC9QsV2jUe8eLM3MUCPYbo6V52eCE436akRIvELq/AqZpxx2bwkq7HC0cRhLB+yaw== integrity sha512-eSXQVCMKU2xc7EcTxe/X/rC9QsV2jUe8eLM3MUCPYbo6V52eCE436akRIvELq/AqZpxx2bwkq7HC0cRhLB+yaw==
@@ -2381,7 +2368,7 @@
csstype "^3.1.3" csstype "^3.1.3"
prop-types "^15.8.1" prop-types "^15.8.1"
"@mui/system@^5.15.14 || ^6.0.0 || ^7.0.0", "@mui/system@^5.16.12", "@mui/system@^5.16.14": "@mui/system@^5.16.12", "@mui/system@^5.16.14":
version "5.16.14" version "5.16.14"
resolved "https://registry.npmjs.org/@mui/system/-/system-5.16.14.tgz" resolved "https://registry.npmjs.org/@mui/system/-/system-5.16.14.tgz"
integrity sha512-KBxMwCb8mSIABnKvoGbvM33XHyT+sN0BzEBG+rsSc0lLQGzs7127KWkCA6/H8h6LZ00XpBEME5MAj8mZLiQ1tw== integrity sha512-KBxMwCb8mSIABnKvoGbvM33XHyT+sN0BzEBG+rsSc0lLQGzs7127KWkCA6/H8h6LZ00XpBEME5MAj8mZLiQ1tw==
@@ -2660,28 +2647,6 @@
resolved "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz" resolved "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz"
integrity sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA== integrity sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==
"@react-google-maps/api@^2.20.7":
version "2.20.7"
resolved "https://registry.npmjs.org/@react-google-maps/api/-/api-2.20.7.tgz"
integrity sha512-ys7uri3V6gjhYZUI43srHzSKDC6/jiKTwHNlwXFTvjeaJE3M3OaYBt9FZKvJs8qnOhL6i6nD1BKJoi1KrnkCkg==
dependencies:
"@googlemaps/js-api-loader" "1.16.8"
"@googlemaps/markerclusterer" "2.5.3"
"@react-google-maps/infobox" "2.20.0"
"@react-google-maps/marker-clusterer" "2.20.0"
"@types/google.maps" "3.58.1"
invariant "2.2.4"
"@react-google-maps/infobox@2.20.0":
version "2.20.0"
resolved "https://registry.npmjs.org/@react-google-maps/infobox/-/infobox-2.20.0.tgz"
integrity sha512-03PJHjohhaVLkX6+NHhlr8CIlvUxWaXhryqDjyaZ8iIqqix/nV8GFdz9O3m5OsjtxtNho09F/15j14yV0nuyLQ==
"@react-google-maps/marker-clusterer@2.20.0":
version "2.20.0"
resolved "https://registry.npmjs.org/@react-google-maps/marker-clusterer/-/marker-clusterer-2.20.0.tgz"
integrity sha512-tieX9Va5w1yP88vMgfH1pHTacDQ9TgDTjox3tLlisKDXRQWdjw+QeVVghhf5XqqIxXHgPdcGwBvKY6UP+SIvLw==
"@react-leaflet/core@^3.0.0": "@react-leaflet/core@^3.0.0":
version "3.0.0" version "3.0.0"
resolved "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz" resolved "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz"
@@ -2907,16 +2872,6 @@
"@svgr/babel-plugin-transform-react-native-svg" "^7.0.0" "@svgr/babel-plugin-transform-react-native-svg" "^7.0.0"
"@svgr/babel-plugin-transform-svg-component" "^7.0.0" "@svgr/babel-plugin-transform-svg-component" "^7.0.0"
"@svgr/core@*", "@svgr/core@^7.0.0":
version "7.0.0"
resolved "https://registry.npmjs.org/@svgr/core/-/core-7.0.0.tgz"
integrity sha512-ztAoxkaKhRVloa3XydohgQQCb0/8x9T63yXovpmHzKMkHO6pkjdsIAWKOS4bE95P/2quVh1NtjSKlMRNzSBffw==
dependencies:
"@babel/core" "^7.21.3"
"@svgr/babel-preset" "^7.0.0"
camelcase "^6.2.0"
cosmiconfig "^8.1.3"
"@svgr/core@^5.5.0": "@svgr/core@^5.5.0":
version "5.5.0" version "5.5.0"
resolved "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz" resolved "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz"
@@ -2926,6 +2881,16 @@
camelcase "^6.2.0" camelcase "^6.2.0"
cosmiconfig "^7.0.0" cosmiconfig "^7.0.0"
"@svgr/core@^7.0.0":
version "7.0.0"
resolved "https://registry.npmjs.org/@svgr/core/-/core-7.0.0.tgz"
integrity sha512-ztAoxkaKhRVloa3XydohgQQCb0/8x9T63yXovpmHzKMkHO6pkjdsIAWKOS4bE95P/2quVh1NtjSKlMRNzSBffw==
dependencies:
"@babel/core" "^7.21.3"
"@svgr/babel-preset" "^7.0.0"
camelcase "^6.2.0"
cosmiconfig "^8.1.3"
"@svgr/hast-util-to-babel-ast@^5.5.0": "@svgr/hast-util-to-babel-ast@^5.5.0":
version "5.5.0" version "5.5.0"
resolved "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz" resolved "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz"
@@ -3029,7 +2994,7 @@
resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz" resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz"
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.9": "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14":
version "7.1.19" version "7.1.19"
resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz" resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz"
integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==
@@ -3137,11 +3102,6 @@
"@types/qs" "*" "@types/qs" "*"
"@types/serve-static" "*" "@types/serve-static" "*"
"@types/google.maps@3.58.1":
version "3.58.1"
resolved "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.58.1.tgz"
integrity sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==
"@types/graceful-fs@^4.1.2": "@types/graceful-fs@^4.1.2":
version "4.1.5" version "4.1.5"
resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz" resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz"
@@ -3149,7 +3109,7 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/hoist-non-react-statics@^3.3.1", "@types/hoist-non-react-statics@>= 3.3.1": "@types/hoist-non-react-statics@^3.3.1":
version "3.3.1" version "3.3.1"
resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz" resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz"
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
@@ -3215,7 +3175,7 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/node@*", "@types/node@>= 12", "@types/node@>=12.12.47", "@types/node@>=13.7.0": "@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
version "22.13.5" version "22.13.5"
resolved "https://registry.npmjs.org/@types/node/-/node-22.13.5.tgz" resolved "https://registry.npmjs.org/@types/node/-/node-22.13.5.tgz"
integrity sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg== integrity sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==
@@ -3257,7 +3217,7 @@
resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz" resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz"
integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==
"@types/react@*", "@types/react@^17.0.0 || ^18.0.0 || ^19.0.0", "@types/react@^18.2.25 || ^19", "@types/react@>= 16", "@types/react@16 || 17 || 18 || 19": "@types/react@*", "@types/react@16 || 17 || 18 || 19":
version "18.3.18" version "18.3.18"
resolved "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz" resolved "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz"
integrity sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ== integrity sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==
@@ -3354,7 +3314,7 @@
dependencies: dependencies:
"@types/yargs-parser" "*" "@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@^4.0.0 || ^5.0.0", "@typescript-eslint/eslint-plugin@^5.5.0": "@typescript-eslint/eslint-plugin@^5.5.0":
version "5.62.0" version "5.62.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz" resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz"
integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==
@@ -3377,7 +3337,7 @@
dependencies: dependencies:
"@typescript-eslint/utils" "5.62.0" "@typescript-eslint/utils" "5.62.0"
"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.5.0": "@typescript-eslint/parser@^5.5.0":
version "5.62.0" version "5.62.0"
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz"
integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==
@@ -3612,16 +3572,16 @@ acorn-walk@^7.1.1:
resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz" resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz"
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.14.0, acorn@^8.2.4, acorn@^8.8.2, acorn@^8.9.0:
version "8.14.0"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz"
integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
acorn@^7.1.1: acorn@^7.1.1:
version "7.4.1" version "7.4.1"
resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.14.0, acorn@^8.2.4, acorn@^8.8.2, acorn@^8.9.0:
version "8.14.0"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz"
integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
address@^1.0.1, address@^1.1.2: address@^1.0.1, address@^1.1.2:
version "1.2.2" version "1.2.2"
resolved "https://registry.npmjs.org/address/-/address-1.2.2.tgz" resolved "https://registry.npmjs.org/address/-/address-1.2.2.tgz"
@@ -3666,7 +3626,7 @@ ajv-keywords@^5.1.0:
dependencies: dependencies:
fast-deep-equal "^3.1.3" fast-deep-equal "^3.1.3"
ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.9.1: ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5:
version "6.12.6" version "6.12.6"
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@@ -3686,7 +3646,7 @@ ajv@^8.0.0:
json-schema-traverse "^1.0.0" json-schema-traverse "^1.0.0"
require-from-string "^2.0.2" require-from-string "^2.0.2"
ajv@^8.6.0, ajv@>=8: ajv@^8.6.0:
version "8.17.1" version "8.17.1"
resolved "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz" resolved "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz"
integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==
@@ -3696,7 +3656,7 @@ ajv@^8.6.0, ajv@>=8:
json-schema-traverse "^1.0.0" json-schema-traverse "^1.0.0"
require-from-string "^2.0.2" require-from-string "^2.0.2"
ajv@^8.8.2, ajv@^8.9.0: ajv@^8.9.0:
version "8.17.1" version "8.17.1"
resolved "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz" resolved "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz"
integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==
@@ -4381,7 +4341,7 @@ browserify-sign@^4.2.3:
readable-stream "^2.3.8" readable-stream "^2.3.8"
safe-buffer "^5.2.1" safe-buffer "^5.2.1"
browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.21.4, browserslist@^4.23.3, browserslist@^4.24.0, browserslist@^4.25.0, "browserslist@>= 4", "browserslist@>= 4.21.0", browserslist@>=4: browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.21.4, browserslist@^4.23.3, browserslist@^4.24.0, browserslist@^4.25.0:
version "4.25.1" version "4.25.1"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz"
integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw== integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==
@@ -5170,7 +5130,7 @@ cssstyle@^2.3.0:
dependencies: dependencies:
cssom "~0.3.6" cssom "~0.3.6"
csstype@^3.0.10, csstype@^3.0.2, csstype@^3.1.3: csstype@^3.0.2, csstype@^3.1.3:
version "3.1.3" version "3.1.3"
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
@@ -5216,14 +5176,14 @@ data-view-byte-offset@^1.0.1:
es-errors "^1.3.0" es-errors "^1.3.0"
is-data-view "^1.0.1" is-data-view "^1.0.1"
"date-fns@^2.25.0 || ^3.2.0 || ^4.0.0", date-fns@^2.30.0, "date-fns@>= 2.x": date-fns@^2.30.0:
version "2.30.0" version "2.30.0"
resolved "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz" resolved "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz"
integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
dependencies: dependencies:
"@babel/runtime" "^7.21.0" "@babel/runtime" "^7.21.0"
dayjs@^1.10.7, dayjs@^1.11.10, dayjs@^1.11.11, "dayjs@>= 1.x": dayjs@^1.11.10, dayjs@^1.11.11:
version "1.11.13" version "1.11.13"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz" resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz"
integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
@@ -6037,7 +5997,7 @@ eslint-webpack-plugin@^3.1.1:
normalize-path "^3.0.0" normalize-path "^3.0.0"
schema-utils "^4.0.0" schema-utils "^4.0.0"
eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", "eslint@^7.5.0 || ^8.0.0", eslint@^8.0.0, eslint@^8.1.0, eslint@^8.3.0, eslint@^8.38.0, "eslint@>= 6", eslint@>=7.0.0, eslint@>=7.28.0: eslint@^8.3.0, eslint@^8.38.0:
version "8.57.1" version "8.57.1"
resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz" resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz"
integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
@@ -7128,7 +7088,7 @@ intl-messageformat@10.7.18:
"@formatjs/icu-messageformat-parser" "2.11.4" "@formatjs/icu-messageformat-parser" "2.11.4"
tslib "^2.8.0" tslib "^2.8.0"
invariant@^2.2.4, invariant@2.2.4: invariant@^2.2.4:
version "2.2.4" version "2.2.4"
resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
@@ -7760,7 +7720,7 @@ jest-resolve-dependencies@^27.5.1:
jest-regex-util "^27.5.1" jest-regex-util "^27.5.1"
jest-snapshot "^27.5.1" jest-snapshot "^27.5.1"
jest-resolve@*, jest-resolve@^27.4.2, jest-resolve@^27.5.1: jest-resolve@^27.4.2, jest-resolve@^27.5.1:
version "27.5.1" version "27.5.1"
resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz"
integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==
@@ -7970,7 +7930,7 @@ jest-worker@^28.0.2:
merge-stream "^2.0.0" merge-stream "^2.0.0"
supports-color "^8.0.0" supports-color "^8.0.0"
"jest@^27.0.0 || ^28.0.0", jest@^27.4.3: jest@^27.4.3:
version "27.5.1" version "27.5.1"
resolved "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz" resolved "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz"
integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==
@@ -8167,11 +8127,6 @@ jwt-decode@^3.1.2:
resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz" resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz"
integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==
kdbush@^4.0.2:
version "4.0.2"
resolved "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz"
integrity sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==
keyv@^4.5.3: keyv@^4.5.3:
version "4.5.4" version "4.5.4"
resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz"
@@ -8214,7 +8169,7 @@ launch-editor@^2.6.0:
picocolors "^1.0.0" picocolors "^1.0.0"
shell-quote "^1.8.1" shell-quote "^1.8.1"
leaflet@^1.9.0, leaflet@^1.9.4: leaflet@^1.9.4:
version "1.9.4" version "1.9.4"
resolved "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz" resolved "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz"
integrity sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA== integrity sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==
@@ -9663,15 +9618,6 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^
resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
"postcss@^7.0.0 || ^8.0.1", postcss@^8, postcss@^8.0.0, postcss@^8.0.3, postcss@^8.0.9, postcss@^8.1.0, postcss@^8.1.4, postcss@^8.2, postcss@^8.2.14, postcss@^8.2.15, postcss@^8.2.2, postcss@^8.3, postcss@^8.3.5, postcss@^8.4, postcss@^8.4.21, postcss@^8.4.33, postcss@^8.4.4, postcss@^8.4.47, postcss@^8.4.6, "postcss@>= 8", postcss@>=8, postcss@>=8.0.9:
version "8.5.3"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz"
integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==
dependencies:
nanoid "^3.3.8"
picocolors "^1.1.1"
source-map-js "^1.2.1"
postcss@^7.0.35: postcss@^7.0.35:
version "7.0.39" version "7.0.39"
resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz" resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz"
@@ -9680,6 +9626,15 @@ postcss@^7.0.35:
picocolors "^0.2.1" picocolors "^0.2.1"
source-map "^0.6.1" source-map "^0.6.1"
postcss@^8.3.5, postcss@^8.4.33, postcss@^8.4.4, postcss@^8.4.47:
version "8.5.3"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz"
integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==
dependencies:
nanoid "^3.3.8"
picocolors "^1.1.1"
source-map-js "^1.2.1"
prelude-ls@^1.2.1: prelude-ls@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
@@ -9697,7 +9652,7 @@ prettier-linter-helpers@^1.0.0:
dependencies: dependencies:
fast-diff "^1.1.2" fast-diff "^1.1.2"
prettier@^2.8.7, prettier@>=2.0.0: prettier@^2.8.7:
version "2.8.8" version "2.8.8"
resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz" resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz"
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
@@ -9759,7 +9714,7 @@ prompts@^2.0.1, prompts@^2.4.2:
kleur "^3.0.3" kleur "^3.0.3"
sisteransi "^1.0.5" sisteransi "^1.0.5"
prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.8.1: prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1" version "15.8.1"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -10317,7 +10272,7 @@ react-dnd@^16.0.1:
fast-deep-equal "^3.1.3" fast-deep-equal "^3.1.3"
hoist-non-react-statics "^3.3.2" hoist-non-react-statics "^3.3.2"
react-dom@*, "react-dom@^16.8 || ^17 || ^18 || ^19", "react-dom@^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^18.0.0 || ^19.0.0", react-dom@^19.0.0, react-dom@^19.2.8, "react-dom@>= 0.14.0", react-dom@>=16.0.0, react-dom@>=16.11.0, react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=16.8.0, react-dom@>=16.9.0, react-dom@>=19.0.0: react-dom@^19.2.8:
version "19.2.8" version "19.2.8"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz" resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz"
integrity sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ== integrity sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==
@@ -10334,21 +10289,6 @@ react-fast-compare@^2.0.1:
resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz" resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz"
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
react-geocode@^0.2.3:
version "0.2.3"
resolved "https://registry.npmjs.org/react-geocode/-/react-geocode-0.2.3.tgz"
integrity sha512-sIpbgmn1IUzAxO4haOZ6jeeFnMD8ya9PC38yiNrmJ9vPWbvAO2D/2yfCBzZjGZVUm4PRzKAc0KghXfaEnug0TQ==
dependencies:
regenerator-runtime "^0.13.3"
react-google-autocomplete@^2.7.3:
version "2.7.4"
resolved "https://registry.npmjs.org/react-google-autocomplete/-/react-google-autocomplete-2.7.4.tgz"
integrity sha512-BeEk2mjzgJcfiCueuKBofm5+RxHUIr0+POn9Yw8merK4Yd0jcOp9Lk/IGJySbz1GTi2Jqvi7V4dbw/DPLD1HMA==
dependencies:
lodash.debounce "^4.0.8"
prop-types "^15.5.0"
react-icons@^4.12.0: react-icons@^4.12.0:
version "4.12.0" version "4.12.0"
resolved "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz" resolved "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz"
@@ -10410,7 +10350,7 @@ react-loading-icons@^1.1.0:
resolved "https://registry.npmjs.org/react-loading-icons/-/react-loading-icons-1.1.0.tgz" resolved "https://registry.npmjs.org/react-loading-icons/-/react-loading-icons-1.1.0.tgz"
integrity sha512-Y9eZ6HAufmUd8DIQd6rFrx5Bt/oDlTM9Nsjvf8YpajTa3dI8cLNU8jUN5z7KTANU+Yd6/KJuBjxVlrU2dMw33g== integrity sha512-Y9eZ6HAufmUd8DIQd6rFrx5Bt/oDlTM9Nsjvf8YpajTa3dI8cLNU8jUN5z7KTANU+Yd6/KJuBjxVlrU2dMw33g==
"react-redux@^7.2.1 || ^8.1.3 || ^9.0.0", react-redux@^9.2.0: react-redux@^9.2.0:
version "9.2.0" version "9.2.0"
resolved "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz" resolved "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz"
integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g== integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==
@@ -10418,7 +10358,7 @@ react-loading-icons@^1.1.0:
"@types/use-sync-external-store" "^0.0.6" "@types/use-sync-external-store" "^0.0.6"
use-sync-external-store "^1.4.0" use-sync-external-store "^1.4.0"
react-refresh@^0.11.0, "react-refresh@>=0.10.0 <1.0.0": react-refresh@^0.11.0:
version "0.11.0" version "0.11.0"
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz" resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz"
integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==
@@ -10438,7 +10378,7 @@ react-router@^6.10.0, react-router@6.29.0:
dependencies: dependencies:
"@remix-run/router" "1.22.0" "@remix-run/router" "1.22.0"
react-scripts@^5.0.1, react-scripts@>=2.1.3: react-scripts@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz" resolved "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz"
integrity sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ== integrity sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==
@@ -10513,7 +10453,7 @@ react-transition-group@^4.4.5:
loose-envify "^1.4.0" loose-envify "^1.4.0"
prop-types "^15.6.2" prop-types "^15.6.2"
react@*, "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ~19", "react@^16.9.0 || ^17.0.0 || ^18 || ^19", "react@^17.0.0 || ^18.0.0 || ^19.0.0", "react@^18 || ^19", "react@^18.0 || ^19", "react@^18.0.0 || ^19.0.0", react@^19.0.0, react@^19.2.8, "react@>= 0.14.0", "react@>= 16", "react@>= 16.14", react@>=16.0.0, react@>=16.11.0, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=16.9.0, react@>=19, react@>=19.0.0, "react@16 || 17 || 18 || 19": react@^19.2.8:
version "19.2.8" version "19.2.8"
resolved "https://registry.npmjs.org/react/-/react-19.2.8.tgz" resolved "https://registry.npmjs.org/react/-/react-19.2.8.tgz"
integrity sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw== integrity sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==
@@ -10582,7 +10522,7 @@ redux@^4.2.0:
dependencies: dependencies:
"@babel/runtime" "^7.9.2" "@babel/runtime" "^7.9.2"
redux@^5.0.0, redux@^5.0.1: redux@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz" resolved "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz"
integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==
@@ -10613,11 +10553,6 @@ regenerate@^1.4.2:
resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz"
integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
regenerator-runtime@^0.13.3:
version "0.13.11"
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
regenerator-runtime@^0.13.9: regenerator-runtime@^0.13.9:
version "0.13.11" version "0.13.11"
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz"
@@ -10801,7 +10736,7 @@ rollup-plugin-terser@^7.0.0:
serialize-javascript "^4.0.0" serialize-javascript "^4.0.0"
terser "^5.0.0" terser "^5.0.0"
"rollup@^1.20.0 || ^2.0.0", rollup@^1.20.0||^2.0.0, rollup@^2.0.0, rollup@^2.43.1: rollup@^2.43.1:
version "2.79.2" version "2.79.2"
resolved "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz" resolved "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz"
integrity sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ== integrity sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==
@@ -11566,7 +11501,7 @@ stylis-plugin-rtl@^2.1.1:
dependencies: dependencies:
cssjanus "^2.0.1" cssjanus "^2.0.1"
stylis@^4.3.4, stylis@4.x: stylis@^4.3.4:
version "4.3.6" version "4.3.6"
resolved "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz" resolved "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz"
integrity sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ== integrity sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==
@@ -11594,13 +11529,6 @@ sucrase@^3.35.0:
pirates "^4.0.1" pirates "^4.0.1"
ts-interface-checker "^0.1.9" ts-interface-checker "^0.1.9"
supercluster@^8.0.1:
version "8.0.1"
resolved "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz"
integrity sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==
dependencies:
kdbush "^4.0.2"
supports-color@^5.3.0: supports-color@^5.3.0:
version "5.5.0" version "5.5.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
@@ -11942,7 +11870,7 @@ type-fest@^0.20.2:
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
type-fest@^0.21.3, "type-fest@>=0.17.0 <4.0.0": type-fest@^0.21.3:
version "0.21.3" version "0.21.3"
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
@@ -12012,11 +11940,6 @@ typedarray-to-buffer@^3.1.5:
dependencies: dependencies:
is-typedarray "^1.0.0" is-typedarray "^1.0.0"
"typescript@^3.2.1 || ^4", typescript@^5.6.0, "typescript@>= 2.7", "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@>=4.9.5:
version "5.9.3"
resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz"
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
ua-parser-js@^1.0.33: ua-parser-js@^1.0.33:
version "1.0.40" version "1.0.40"
resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz" resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz"
@@ -12257,7 +12180,7 @@ webpack-dev-middleware@^5.3.4:
range-parser "^1.2.1" range-parser "^1.2.1"
schema-utils "^4.0.0" schema-utils "^4.0.0"
webpack-dev-server@^4.6.0, "webpack-dev-server@3.x || 4.x": webpack-dev-server@^4.6.0:
version "4.15.2" version "4.15.2"
resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz" resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz"
integrity sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g== integrity sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==
@@ -12322,7 +12245,7 @@ webpack-sources@^3.2.3:
resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz" resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz"
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
"webpack@^4.0.0 || ^5.0.0", "webpack@^4.37.0 || ^5.0.0", "webpack@^4.4.0 || ^5.9.0", "webpack@^4.44.2 || ^5.47.0", webpack@^5.0.0, webpack@^5.1.0, webpack@^5.20.0, webpack@^5.64.4, "webpack@>= 4", webpack@>=2, "webpack@>=4.43.0 <6.0.0": webpack@^5.64.4:
version "5.98.0" version "5.98.0"
resolved "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz" resolved "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz"
integrity sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA== integrity sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==