Compare commits
2 Commits
79fefda61a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| c544cefe89 | |||
| 6ed0e577e0 |
3
.env
3
.env
@@ -4,9 +4,6 @@ GENERATE_SOURCEMAP = false
|
||||
## Backend API URL
|
||||
REACT_APP_API_URL=https://mock-data-api-nextjs.vercel.app/
|
||||
|
||||
## Google Map Key
|
||||
|
||||
REACT_APP_GOOGLE_MAPS_API_KEY=AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8
|
||||
REACT_APP_RIDER_ACCESS_ID=AAAAILMpCEU:APA91bEavuOllBI6sFgYtxXAgNmAVwNA-MnCMHLGlR4_t7UqpLajAkdn3T0CZr_zaLBknLyim9ytFLMZgbeXmKqTad_PKCbqlYjHpaizVrLXtecxqyEy4UktIacK2UvHVUATHL-7VQQk
|
||||
## Firebase - Google Auth
|
||||
|
||||
|
||||
189
package-lock.json
generated
189
package-lock.json
generated
@@ -13,13 +13,11 @@
|
||||
"@astryxdesign/core": "^0.1.9",
|
||||
"@astryxdesign/theme-neutral": "^0.1.9",
|
||||
"@custom-react-hooks/use-network": "^1.0.1",
|
||||
"@react-google-maps/api": "^2.20.7",
|
||||
"@reduxjs/toolkit": "^2.12.0",
|
||||
"@stylexjs/stylex": "^0.19.0",
|
||||
"@svgr/webpack": "^7.0.0",
|
||||
"@tanstack/react-query": "^5.22.2",
|
||||
"antd": "^5.11.5",
|
||||
"autosuggest-highlight": "^3.3.4",
|
||||
"axios": "^1.3.5",
|
||||
"buffer": "^6.0.3",
|
||||
"chance": "^1.1.11",
|
||||
@@ -45,8 +43,6 @@
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "^19.2.8",
|
||||
"react-geocode": "^0.2.3",
|
||||
"react-google-autocomplete": "^2.7.3",
|
||||
"react-icons": "^4.12.0",
|
||||
"react-intl": "^7.1.14",
|
||||
"react-leaflet": "^5.0.0",
|
||||
@@ -2714,22 +2710,6 @@
|
||||
"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/@humanwhocodes/config-array": {
|
||||
"version": "0.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
||||
@@ -3786,36 +3766,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
|
||||
"integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA=="
|
||||
},
|
||||
"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": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz",
|
||||
@@ -4647,12 +4597,6 @@
|
||||
"@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": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
||||
@@ -5727,14 +5671,6 @@
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/autosuggest-highlight": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/autosuggest-highlight/-/autosuggest-highlight-3.3.4.tgz",
|
||||
"integrity": "sha512-j6RETBD2xYnrVcoV1S5R4t3WxOlWZKyDQjkwnggDPSjF5L4jV98ZltBpvPvbkM1HtoSe5o+bNrTHyjPbieGeYA==",
|
||||
"dependencies": {
|
||||
"remove-accents": "^0.4.2"
|
||||
}
|
||||
},
|
||||
"node_modules/available-typed-arrays": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
|
||||
@@ -13295,12 +13231,6 @@
|
||||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz",
|
||||
"integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="
|
||||
},
|
||||
"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/kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
@@ -16781,26 +16711,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
|
||||
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
||||
},
|
||||
"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==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.13.3"
|
||||
}
|
||||
},
|
||||
"node_modules/react-google-autocomplete": {
|
||||
"version": "2.7.3",
|
||||
"resolved": "https://registry.npmjs.org/react-google-autocomplete/-/react-google-autocomplete-2.7.3.tgz",
|
||||
"integrity": "sha512-Nm+7/VDe7/NDWb8p/a39is7ktNqt5bNqAOoQv2Ev/XkuEvjsRk08VAPFmXUH03xKuM8IUuDrk2Lwfge44YEj6Q==",
|
||||
"dependencies": {
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"prop-types": "^15.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz",
|
||||
@@ -17568,11 +17478,6 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/remove-accents": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.4.tgz",
|
||||
"integrity": "sha512-EpFcOa/ISetVHEXqu+VwI96KZBmq+a8LJnGkaeFw45epGlxIZz5dhEEnNZMsQXgORu3qaMoLX4qJCzOik6ytAg=="
|
||||
},
|
||||
"node_modules/renderkid": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz",
|
||||
@@ -18626,15 +18531,6 @@
|
||||
"stylis": "4.x"
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
@@ -21997,20 +21893,6 @@
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"@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=="
|
||||
},
|
||||
"@googlemaps/markerclusterer": {
|
||||
"version": "2.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@googlemaps/markerclusterer/-/markerclusterer-2.5.3.tgz",
|
||||
"integrity": "sha512-x7lX0R5yYOoiNectr10wLgCBasNcXFHiADIBdmn7jQllF2B5ENQw5XtZK+hIw4xnV0Df0xhN4LN98XqA5jaiOw==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"supercluster": "^8.0.1"
|
||||
}
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
||||
@@ -22759,29 +22641,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
|
||||
"integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA=="
|
||||
},
|
||||
"@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==",
|
||||
"requires": {
|
||||
"@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": {
|
||||
"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": {
|
||||
"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": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz",
|
||||
@@ -23343,11 +23202,6 @@
|
||||
"@types/range-parser": "*"
|
||||
}
|
||||
},
|
||||
"@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=="
|
||||
},
|
||||
"@types/graceful-fs": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
||||
@@ -24187,14 +24041,6 @@
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"autosuggest-highlight": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/autosuggest-highlight/-/autosuggest-highlight-3.3.4.tgz",
|
||||
"integrity": "sha512-j6RETBD2xYnrVcoV1S5R4t3WxOlWZKyDQjkwnggDPSjF5L4jV98ZltBpvPvbkM1HtoSe5o+bNrTHyjPbieGeYA==",
|
||||
"requires": {
|
||||
"remove-accents": "^0.4.2"
|
||||
}
|
||||
},
|
||||
"available-typed-arrays": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
|
||||
@@ -29646,11 +29492,6 @@
|
||||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz",
|
||||
"integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="
|
||||
},
|
||||
"kdbush": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz",
|
||||
"integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA=="
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
@@ -31952,23 +31793,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
|
||||
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
||||
},
|
||||
"react-geocode": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-geocode/-/react-geocode-0.2.3.tgz",
|
||||
"integrity": "sha512-sIpbgmn1IUzAxO4haOZ6jeeFnMD8ya9PC38yiNrmJ9vPWbvAO2D/2yfCBzZjGZVUm4PRzKAc0KghXfaEnug0TQ==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.3"
|
||||
}
|
||||
},
|
||||
"react-google-autocomplete": {
|
||||
"version": "2.7.3",
|
||||
"resolved": "https://registry.npmjs.org/react-google-autocomplete/-/react-google-autocomplete-2.7.3.tgz",
|
||||
"integrity": "sha512-Nm+7/VDe7/NDWb8p/a39is7ktNqt5bNqAOoQv2Ev/XkuEvjsRk08VAPFmXUH03xKuM8IUuDrk2Lwfge44YEj6Q==",
|
||||
"requires": {
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"prop-types": "^15.5.0"
|
||||
}
|
||||
},
|
||||
"react-icons": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz",
|
||||
@@ -32476,11 +32300,6 @@
|
||||
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
||||
"integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog=="
|
||||
},
|
||||
"remove-accents": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.4.tgz",
|
||||
"integrity": "sha512-EpFcOa/ISetVHEXqu+VwI96KZBmq+a8LJnGkaeFw45epGlxIZz5dhEEnNZMsQXgORu3qaMoLX4qJCzOik6ytAg=="
|
||||
},
|
||||
"renderkid": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz",
|
||||
@@ -33272,14 +33091,6 @@
|
||||
"cssjanus": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"supercluster": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz",
|
||||
"integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==",
|
||||
"requires": {
|
||||
"kdbush": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
|
||||
@@ -8,13 +8,11 @@
|
||||
"@astryxdesign/core": "^0.1.9",
|
||||
"@astryxdesign/theme-neutral": "^0.1.9",
|
||||
"@custom-react-hooks/use-network": "^1.0.1",
|
||||
"@react-google-maps/api": "^2.20.7",
|
||||
"@reduxjs/toolkit": "^2.12.0",
|
||||
"@stylexjs/stylex": "^0.19.0",
|
||||
"@svgr/webpack": "^7.0.0",
|
||||
"@tanstack/react-query": "^5.22.2",
|
||||
"antd": "^5.11.5",
|
||||
"autosuggest-highlight": "^3.3.4",
|
||||
"axios": "^1.3.5",
|
||||
"buffer": "^6.0.3",
|
||||
"chance": "^1.1.11",
|
||||
@@ -40,8 +38,6 @@
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "^19.2.8",
|
||||
"react-geocode": "^0.2.3",
|
||||
"react-google-autocomplete": "^2.7.3",
|
||||
"react-icons": "^4.12.0",
|
||||
"react-intl": "^7.1.14",
|
||||
"react-leaflet": "^5.0.0",
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
|
||||
<!-- 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://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>
|
||||
.datedialog > div > div > .MuiPaper-root {
|
||||
|
||||
@@ -8,7 +8,7 @@ import Notistack from 'components/third-party/Notistack';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { useEffect } from 'react';
|
||||
import InternetStatus from 'components/nearle_components/updateNetworkStatus';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
// auth-provider
|
||||
// import { JWTProvider as AuthProvider } from 'contexts/JWTContext';
|
||||
|
||||
@@ -25,14 +25,13 @@ const AppSideNav = ({ isCollapsed, onCollapsedChange }) => {
|
||||
// Wrap explicitly in Astryx's own <Icon> rather than passing the bare
|
||||
// component and letting SideNavItem's renderIconSlot auto-detect it:
|
||||
// that detection only matches plain functions/forwardRef objects, not
|
||||
// React.memo-wrapped ones (several @ant-design/icons v5 icons, as well
|
||||
// as @mui/icons-material icons, are memo-wrapped) — those fell through
|
||||
// React.memo-wrapped ones (several @ant-design/icons v5 icons are
|
||||
// memo-wrapped) — those fell through
|
||||
// and got returned as a raw, uninstantiated element, crashing with
|
||||
// "Objects are not valid as a React child". Wrapping here always
|
||||
// renders through Icon's own component-mode path, which handles any
|
||||
// component type and gives every icon the same normalised size/colour
|
||||
// regardless of source library (this menu mixes @ant-design/icons and
|
||||
// @mui/icons-material).
|
||||
// regardless of source library.
|
||||
const icon = item.icon ? <Icon icon={item.icon} /> : undefined;
|
||||
|
||||
if (item.type === 'collapse') {
|
||||
|
||||
@@ -5,7 +5,6 @@ import { TopNav, TopNavHeading } from '@astryxdesign/core/TopNav';
|
||||
import { DropdownMenu } from '@astryxdesign/core/DropdownMenu';
|
||||
import { Avatar } from '@astryxdesign/core/Avatar';
|
||||
import { HStack } from '@astryxdesign/core/HStack';
|
||||
import { Text } from '@astryxdesign/core/Text';
|
||||
|
||||
import { WindowsOutlined, EditOutlined, LogoutOutlined } from '@ant-design/icons';
|
||||
import { TbBoxMultiple1 } from 'react-icons/tb';
|
||||
@@ -31,7 +30,6 @@ const AppTopNav = () => {
|
||||
const topNavRef = useRef(null);
|
||||
const [headerHeight, setHeaderHeight] = useState(null);
|
||||
|
||||
const tenantname = localStorage.getItem('tenantname') || '';
|
||||
const fullname = localStorage.getItem('fullname') || '';
|
||||
|
||||
const handleLogout = () => {
|
||||
|
||||
@@ -6,42 +6,8 @@ import { TbListDetails } from 'react-icons/tb';
|
||||
import { LiaFileInvoiceSolid } from 'react-icons/lia';
|
||||
import { MdDirectionsBike as DirectionsBikeOutlinedIcon, MdRoute as RouteOutlinedIcon, MdMoped as MopedOutlinedIcon } from 'react-icons/md';
|
||||
|
||||
// assets
|
||||
import {
|
||||
BorderOutlined,
|
||||
BoxPlotOutlined,
|
||||
ChromeOutlined,
|
||||
DeploymentUnitOutlined,
|
||||
GatewayOutlined,
|
||||
MenuUnfoldOutlined,
|
||||
QuestionOutlined,
|
||||
SmileOutlined,
|
||||
StopOutlined,
|
||||
DashboardOutlined,
|
||||
ClockCircleOutlined,
|
||||
UserOutlined,
|
||||
SettingOutlined
|
||||
} from '@ant-design/icons';
|
||||
import { Path } from 'leaflet';
|
||||
import { MdLocationOn as LocationOnOutlined } from 'react-icons/md';
|
||||
|
||||
// icons
|
||||
const icons = {
|
||||
ChromeOutlined,
|
||||
MenuUnfoldOutlined,
|
||||
BoxPlotOutlined,
|
||||
StopOutlined,
|
||||
BorderOutlined,
|
||||
SmileOutlined,
|
||||
GatewayOutlined,
|
||||
QuestionOutlined,
|
||||
DeploymentUnitOutlined,
|
||||
DashboardOutlined,
|
||||
ClockCircleOutlined,
|
||||
UserOutlined,
|
||||
SettingOutlined
|
||||
};
|
||||
|
||||
// ==============================|| MENU ITEMS - SUPPORT ||============================== //
|
||||
|
||||
const nearle = {
|
||||
|
||||
@@ -94,7 +94,7 @@ export const fetchDeliveryLocationSummary = async () => {
|
||||
// fetchOrders.js
|
||||
|
||||
export const fetchOrders1 = async ({ pageParam = 1, queryKey }) => {
|
||||
const [_key, tenantid, locationid, status, startdate, enddate, searchword, rowsPerPage] = queryKey;
|
||||
const [, tenantid, locationid, status, startdate, enddate, searchword, rowsPerPage] = queryKey;
|
||||
|
||||
const res = await axios.get(
|
||||
`${process.env.REACT_APP_URL}/orders/tenant/getorders/?tenantid=${tenantid}&locationid=${locationid}&status=${status}&fromdate=${startdate}&todate=${enddate}&pageno=${pageParam}&pagesize=${rowsPerPage}&keyword=${searchword}`
|
||||
@@ -224,7 +224,7 @@ export const gettenantlocations = async ({ queryKey }) => {
|
||||
|
||||
// ==============================|| fetchDeliverySummary (orders summary)||============================== //
|
||||
export const fetchDeliverySummary = async ({ queryKey }) => {
|
||||
const [, startdate, enddate, currentStatus, locationId] = queryKey;
|
||||
const [, startdate, enddate, , locationId] = queryKey;
|
||||
const response = await axios.get(
|
||||
`${process.env.REACT_APP_URL}/deliveries/deliverysummary?tenantid=${tenid}&locationid=${locationId}&fromdate=${startdate}&todate=${enddate}`
|
||||
);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { React, useEffect, useState } from 'react';
|
||||
import { React, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { Button } from '@astryxdesign/core/Button';
|
||||
import { TextInput } from '@astryxdesign/core/TextInput';
|
||||
import { Typeahead } from '@astryxdesign/core/Typeahead';
|
||||
import { HStack } from '@astryxdesign/core/HStack';
|
||||
import { Text } from '@astryxdesign/core/Text';
|
||||
|
||||
@@ -11,7 +12,7 @@ import MainCard from 'components/MainCard';
|
||||
import axios from 'axios';
|
||||
|
||||
import Loader from 'components/Loader';
|
||||
import Geocode from 'react-geocode';
|
||||
import { createAddressSearchSource } from '../../../utils/addressSearch';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { useNavigate } from 'react-router';
|
||||
import TitleCard from '../titleCard';
|
||||
@@ -24,45 +25,26 @@ const FieldGrid = ({ children }) => (
|
||||
|
||||
const CreateCustomer = () => {
|
||||
const appId = localStorage.getItem('applocationid');
|
||||
const [selectedImage, setSelectedImage] = useState(undefined);
|
||||
const [avatar, setAvatar] = useState();
|
||||
const [businessname, setBusinessname] = useState('');
|
||||
const [businessno, setBusinessno] = useState('');
|
||||
const [selectedImage] = useState(undefined);
|
||||
const [, setAvatar] = useState();
|
||||
const [mobilenumber, setMobilenumber] = useState('');
|
||||
const [emailaddress, setEmailaddress] = useState('');
|
||||
const [city, setCity] = useState('');
|
||||
const [zipcode, setZipcode] = useState('');
|
||||
const [address, setAddress] = useState('');
|
||||
const [suburb, setSuburb] = useState('');
|
||||
const [latlong, setLatlong] = useState({});
|
||||
const [firstname, setFirstname] = useState('');
|
||||
const [doorno, setDoorno] = useState('');
|
||||
const [landmark, setLandmark] = useState('');
|
||||
const [tenantinfo, setTenantinfo] = useState({});
|
||||
const [inputValue2, setInputValue2] = useState('');
|
||||
const [, setTenantinfo] = useState({});
|
||||
const [pickPlace, setPickPlace] = useState(null);
|
||||
const [appLocaLat, setAppLocaLat] = useState();
|
||||
const [appLocaLng, setAppLocaLng] = useState();
|
||||
const [appLocaRadius, setAppLocaRadius] = useState();
|
||||
const [locaName, setLocoName] = useState('Select Location');
|
||||
const [locations, setLocations] = useState('Select Location');
|
||||
const [tenantlist, setTenantlist] = useState([]);
|
||||
const [, setLocations] = useState('Select Location');
|
||||
const userid = localStorage.getItem('userid');
|
||||
const [isAppLocation, setIsAppLocation] = useState(false);
|
||||
const [tenantLocations, setTenantlocations] = useState([]);
|
||||
const [isClient, setisclient] = useState(false);
|
||||
const [tid, setTid] = useState(0);
|
||||
const [isBusiness, setIsBusiness] = useState(false);
|
||||
const [tenanatLocoId, setTenanatLocoId] = useState(localStorage.getItem('locationid'));
|
||||
const [tenantlocation, setTenantlocation] = useState('');
|
||||
const [isLocation, setIsLocation] = useState(false);
|
||||
const [tid] = useState(0);
|
||||
const [pickCust, setPickCust] = useState({});
|
||||
const [startPoint, setStartPoint] = useState({ latitude: 0, longitude: 0 });
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
||||
// Geocode.setApiKey('AIzaSyCF4KatYCI3vqz1_H3kiHeyS3yCMfYToh8');
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -71,91 +53,89 @@ const CreateCustomer = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// 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),
|
||||
// Nominatim search source, soft-biased toward the operator's zone once
|
||||
// getapplocations() resolves appLocaLat/appLocaLng — replaces the Google
|
||||
// Places Autocomplete bound to #addressAuto1.
|
||||
const pickAddressSource = useMemo(
|
||||
() => createAddressSearchSource({ bias: { lat: appLocaLat, lng: appLocaLng } }),
|
||||
[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}`);
|
||||
logger.info('new place', place); // Do something with the selected place
|
||||
logger.info(' pick (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place
|
||||
// to trigger getDistance
|
||||
setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
|
||||
setAddress(`${place.name} ${place.formatted_address}`);
|
||||
setPickCust({ ...pickCust, address: `${place.name} ${place.formatted_address}` });
|
||||
const address = {
|
||||
address: `${place.name} ${place.formatted_address}`,
|
||||
street_number: '',
|
||||
route: '',
|
||||
locality: '',
|
||||
sublocality_level_1: '',
|
||||
administrative_area_level_3: '',
|
||||
administrative_area_level_1: '',
|
||||
country: '',
|
||||
postal_code: ''
|
||||
};
|
||||
place.address_components.forEach((component) => {
|
||||
component.types.forEach((type) => {
|
||||
switch (type) {
|
||||
case 'street_number':
|
||||
address.street_number = component.long_name;
|
||||
break;
|
||||
case 'route':
|
||||
address.route = component.long_name;
|
||||
break;
|
||||
case 'locality':
|
||||
address.locality = component.long_name;
|
||||
break;
|
||||
case 'sublocality_level_1':
|
||||
address.sublocality_level_1 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_3':
|
||||
address.administrative_area_level_3 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_1':
|
||||
address.administrative_area_level_1 = component.long_name;
|
||||
break;
|
||||
case 'country':
|
||||
address.country = component.long_name;
|
||||
break;
|
||||
case 'postal_code':
|
||||
address.postal_code = component.long_name;
|
||||
break;
|
||||
// Add more cases as needed for other types
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Use address object as per your requirements
|
||||
setPickCust({
|
||||
...pickCust,
|
||||
address: address.address,
|
||||
doorno: `${address.street_number} ${address.route}`,
|
||||
suburb: address.administrative_area_level_3,
|
||||
city: address.locality,
|
||||
state: address.administrative_area_level_1,
|
||||
postcode: address.postal_code,
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
logger.info('Pick Address:', address);
|
||||
const handlePickPlaceSelected = (item) => {
|
||||
setPickPlace(item);
|
||||
if (!item) {
|
||||
setPickCust({
|
||||
...pickCust,
|
||||
doorno: '',
|
||||
suburb: '',
|
||||
city: '',
|
||||
postcode: '',
|
||||
landmark: ''
|
||||
});
|
||||
setStartPoint({ latitude: 0, longitude: 0 });
|
||||
return;
|
||||
}
|
||||
}, [inputValue2]);
|
||||
const place = item.auxiliaryData;
|
||||
logger.info('pick (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() });
|
||||
setStartPoint({ latitude: place.geometry.location.lat(), longitude: place.geometry.location.lng() });
|
||||
setAddress(`${place.name} ${place.formatted_address}`);
|
||||
const address = {
|
||||
address: `${place.name} ${place.formatted_address}`,
|
||||
street_number: '',
|
||||
route: '',
|
||||
locality: '',
|
||||
sublocality_level_1: '',
|
||||
administrative_area_level_3: '',
|
||||
administrative_area_level_1: '',
|
||||
country: '',
|
||||
postal_code: ''
|
||||
};
|
||||
place.address_components.forEach((component) => {
|
||||
component.types.forEach((type) => {
|
||||
switch (type) {
|
||||
case 'street_number':
|
||||
address.street_number = component.long_name;
|
||||
break;
|
||||
case 'route':
|
||||
address.route = component.long_name;
|
||||
break;
|
||||
case 'locality':
|
||||
address.locality = component.long_name;
|
||||
break;
|
||||
case 'sublocality_level_1':
|
||||
address.sublocality_level_1 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_3':
|
||||
address.administrative_area_level_3 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_1':
|
||||
address.administrative_area_level_1 = component.long_name;
|
||||
break;
|
||||
case 'country':
|
||||
address.country = component.long_name;
|
||||
break;
|
||||
case 'postal_code':
|
||||
address.postal_code = component.long_name;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
setPickCust({
|
||||
...pickCust,
|
||||
address: address.address,
|
||||
doorno: `${address.street_number} ${address.route}`,
|
||||
suburb: address.administrative_area_level_3,
|
||||
city: address.locality,
|
||||
state: address.administrative_area_level_1,
|
||||
postcode: address.postal_code,
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
logger.info('Pick Address:', address);
|
||||
};
|
||||
// ==================================================== || getapplocations || ====================================================
|
||||
const getapplocations = async () => {
|
||||
setLoading(true);
|
||||
@@ -163,12 +143,10 @@ const CreateCustomer = () => {
|
||||
.get(`${process.env.REACT_APP_URL}/utils/getapplocations/?applocationid=${appId}`)
|
||||
.then((res) => {
|
||||
logger.info('getapplocations', res);
|
||||
const { opentime, closetime, latitude, longitude, radius } = res.data.details?.[0] || {};
|
||||
const { latitude, longitude } = res.data.details?.[0] || {};
|
||||
if (res.data.status) {
|
||||
setAppLocaLat(latitude);
|
||||
setAppLocaLng(longitude);
|
||||
setAppLocaRadius(radius);
|
||||
logger.info('radius', radius);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
@@ -202,50 +180,6 @@ const CreateCustomer = () => {
|
||||
|
||||
// ===================================================== || fetchtenantinfolist || =====================================================
|
||||
|
||||
const fetchtenantinfolist = async (id) => {
|
||||
setLoading(true);
|
||||
await axios
|
||||
.get(`${process.env.REACT_APP_URL}/tenants/gettenants/?applocationid=${id}&status=active`)
|
||||
|
||||
.then((res) => {
|
||||
logger.info(res);
|
||||
if (res.data.status) {
|
||||
let arr = [];
|
||||
res.data.details.map((val) => {
|
||||
arr.push({
|
||||
...val,
|
||||
label: `${val.tenantname}`
|
||||
});
|
||||
});
|
||||
setTenantlist(arr);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(err);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
// ============================================= || gettenantlocations (branches) || =============================================
|
||||
const gettenantlocations = async (id) => {
|
||||
try {
|
||||
const res = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantlocations/?tenantid=${id}`);
|
||||
logger.info('gettenantlocations', res.data.details);
|
||||
if (res.data.details.length == 1) {
|
||||
setIsLocation(true);
|
||||
setTenantlocations(res.data.details);
|
||||
setTenanatLocoId(res.data.details[0].locationid);
|
||||
setTenantlocation(res.data.details[0].locationaddress); //client address
|
||||
setIsBusiness(true);
|
||||
} else {
|
||||
setTenantlocations(res.data.details);
|
||||
setIsBusiness(false); // became true after select from tenanatLocations
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('gettenantlocations', err);
|
||||
}
|
||||
};
|
||||
|
||||
const opentoast = (message) => {
|
||||
enqueueSnackbar(message, {
|
||||
variant: 'error',
|
||||
@@ -399,26 +333,15 @@ const CreateCustomer = () => {
|
||||
</FieldGrid>
|
||||
|
||||
{/* ===================================================== || Address || ===================================================== */}
|
||||
<TextInput
|
||||
<Typeahead
|
||||
label="Address"
|
||||
id="addressAuto1"
|
||||
width="100%"
|
||||
hasClear
|
||||
value={inputValue2}
|
||||
onChange={(v) => {
|
||||
setInputValue2(v);
|
||||
if (!v) {
|
||||
setPickCust({
|
||||
...pickCust,
|
||||
doorno: '',
|
||||
suburb: '',
|
||||
city: '',
|
||||
postcode: '',
|
||||
landmark: ''
|
||||
});
|
||||
setStartPoint({ latitude: 0, longitude: 0 });
|
||||
}
|
||||
}}
|
||||
debounceMs={500}
|
||||
placeholder="Search address"
|
||||
searchSource={pickAddressSource}
|
||||
value={pickPlace}
|
||||
onChange={handlePickPlaceSelected}
|
||||
/>
|
||||
|
||||
<FieldGrid>
|
||||
|
||||
@@ -33,7 +33,6 @@ import { useHotkeyFocus } from 'components/nearle_components/useHotkeyFocus';
|
||||
import DateFilterDialog from 'components/nearle_components/DateFilterDialog';
|
||||
import CircularLoader from 'components/nearle_components/CircularLoader';
|
||||
import { useQuery, useInfiniteQuery } from '@tanstack/react-query';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import logger from 'utils/logger';
|
||||
// ============================================================================
|
||||
@@ -201,7 +200,6 @@ const MetricCell = ({ value, color, icon, isMoney = false }) => {
|
||||
const noWrapStyle = { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' };
|
||||
|
||||
const Deliveries = () => {
|
||||
const navigate = useNavigate();
|
||||
const tid = localStorage.getItem('tenantid');
|
||||
const loadMoreRef = useRef();
|
||||
const containerRef = useRef();
|
||||
|
||||
@@ -107,7 +107,7 @@ const ActiveSection = ({
|
||||
);
|
||||
}
|
||||
|
||||
const renderActiveDeliveryCard = (o, i) => {
|
||||
const renderActiveDeliveryCard = (o) => {
|
||||
const rid = o.rider_id || o.userid;
|
||||
const rider = riders.find((r) => String(r.id) === String(rid));
|
||||
const color = getRiderColor(rid);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react';
|
||||
import { MapContainer, TileLayer, Marker, Popup, Polyline, Tooltip, useMap, useMapEvents, ZoomControl } from 'react-leaflet';
|
||||
import { MapContainer, TileLayer, Marker, Popup, Polyline, Tooltip, useMap, ZoomControl } from 'react-leaflet';
|
||||
import L from 'leaflet';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
// Side-effect import: patches L.Polyline so pathOptions.offset (in screen px)
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
MdStraighten,
|
||||
MdLocationOn,
|
||||
MdMarkunreadMailbox,
|
||||
MdMoveToInbox,
|
||||
MdPerson,
|
||||
MdPlace,
|
||||
MdTwoWheeler,
|
||||
@@ -40,10 +39,7 @@ import {
|
||||
MdChevronLeft,
|
||||
MdChevronRight,
|
||||
MdLocalMall,
|
||||
MdCheckCircle,
|
||||
MdErrorOutline,
|
||||
MdWarning,
|
||||
MdClose,
|
||||
MdFormatListBulleted,
|
||||
MdTimer,
|
||||
MdCalendarToday,
|
||||
@@ -52,7 +48,6 @@ import {
|
||||
} from 'react-icons/md';
|
||||
import { fetchDeliveries, fetchAppLocations, getRiderPeriodicLogs, fetchRidersLogs, fetchBatchEfficiency } from '../api/api';
|
||||
import {
|
||||
STATUS_STYLES,
|
||||
getStatusStyle,
|
||||
FINAL_STATUSES,
|
||||
SKIPPED_STATUSES,
|
||||
@@ -229,11 +224,6 @@ const getRowBatch = (r, fieldId = 'all', batches = BATCHES_DEFAULT) => {
|
||||
// the operator clicks empty map space. Markers' click events do NOT bubble
|
||||
// to the map, so this only fires on background clicks (which is what we
|
||||
// want — clicking elsewhere should release the pin).
|
||||
function CompareMapClickUnpin({ onUnpin }) {
|
||||
useMapEvents({ click: () => onUnpin() });
|
||||
return null;
|
||||
}
|
||||
|
||||
// Captures the Leaflet map instance for the parent component via a ref. Kept
|
||||
// available even after the two-map Compare layout was unified into one map,
|
||||
// since future per-step imperative zoom logic still needs a handle on the
|
||||
@@ -751,14 +741,6 @@ const ANALYSIS_BATCH_WINDOWS = [
|
||||
{ key: 'evening', label: 'Evening', timeRange: '4:00 PM – 7:00 PM', sub: 'Dinner & end-of-day', color: '#6366f1', bg: '#eef2ff', border: '#c7d2fe' }
|
||||
];
|
||||
|
||||
// Tolerant field-name lookup so the Analysis card still renders cleanly even
|
||||
// if the API response uses slightly different keys than expected.
|
||||
const analysisPick = (obj, keys) => {
|
||||
for (const k of keys) {
|
||||
if (obj && obj[k] != null && obj[k] !== '') return obj[k];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
const analysisFormatNum = (v) => {
|
||||
if (v == null) return '—';
|
||||
if (typeof v === 'number') return v.toLocaleString('en-IN');
|
||||
@@ -766,14 +748,6 @@ const analysisFormatNum = (v) => {
|
||||
if (Number.isFinite(n)) return n.toLocaleString('en-IN');
|
||||
return String(v);
|
||||
};
|
||||
const analysisFormatKm = (v) => (v == null ? '—' : `${parseFloat(v).toFixed(1)} km`);
|
||||
const analysisFormatRupees = (v) => (v == null ? '—' : `₹${parseFloat(v).toFixed(0)}`);
|
||||
const analysisFormatPct = (v) => {
|
||||
if (v == null) return '—';
|
||||
const n = parseFloat(v);
|
||||
if (!Number.isFinite(n)) return '—';
|
||||
return `${n > 1 ? n.toFixed(1) : (n * 100).toFixed(1)}%`;
|
||||
};
|
||||
|
||||
const Dispatch = ({
|
||||
data,
|
||||
@@ -795,7 +769,7 @@ const Dispatch = ({
|
||||
// map + sidebar UI) or 'analysis' (batch efficiency panel). Embedded use
|
||||
// (Preview) never reaches the Analysis switcher, so default doesn't matter
|
||||
// there.
|
||||
const [topView, setTopView] = useState('live');
|
||||
const [topView] = useState('live');
|
||||
const [analysisResults, setAnalysisResults] = useState({});
|
||||
const [analysisLoadingWindow, setAnalysisLoadingWindow] = useState(null);
|
||||
const [activeBatchKey, setActiveBatchKey] = useState(null);
|
||||
@@ -833,7 +807,7 @@ const Dispatch = ({
|
||||
// Single delivery stop pinned by clicking its sidebar row — overrides the rider's full-route bounds on the map.
|
||||
const [focusedStop, setFocusedStop] = useState(null);
|
||||
// Fly-to target set by ActiveSection card clicks — zooms the map without touching sidebar or popup.
|
||||
const [activeFlyTo, setActiveFlyTo] = useState(null);
|
||||
const [activeFlyTo] = useState(null);
|
||||
// How the stops inside each trip block are ordered in the focused-rider sidebar:
|
||||
// 'planned' → the dispatched route order (by step) — the default.
|
||||
// 'time' → re-sorted by when each delivery was actually completed, so the
|
||||
@@ -863,7 +837,6 @@ const Dispatch = ({
|
||||
// Short-lived close timer for the general map order/marker popups.
|
||||
// Gives the cursor a ~200ms window to travel from the marker onto the popup
|
||||
// or vice versa without immediately triggering a close.
|
||||
const activePopupMarkerRef = useRef(null);
|
||||
const popupHoverTimerRef = useRef(null);
|
||||
// Order shown in the centered popup overlay. Rendered outside the leaflet
|
||||
// map (see `dispatch-popup-center` overlay near the bottom of the JSX) so
|
||||
@@ -887,9 +860,7 @@ const Dispatch = ({
|
||||
// The user's last-picked location is mirrored into localStorage so it
|
||||
// survives reloads and stays in sync with other pages that read it.
|
||||
const initialAppLocationId = typeof window !== 'undefined' ? localStorage.getItem('applocationid') : null;
|
||||
const [selectedAppLocationId, setSelectedAppLocationId] = useState(
|
||||
initialAppLocationId != null ? Number(initialAppLocationId) : 0
|
||||
);
|
||||
const [selectedAppLocationId] = useState(initialAppLocationId != null ? Number(initialAppLocationId) : 0);
|
||||
const [locationMenuOpen, setLocationMenuOpen] = useState(false);
|
||||
const locationMenuRef = useRef(null);
|
||||
|
||||
@@ -897,7 +868,7 @@ const Dispatch = ({
|
||||
// orders bucket into Morning/Afternoon/Evening by when they were assigned,
|
||||
// per current spec. The status-wise time-field dropdown is hidden for now
|
||||
// (see commented-out block in JSX), so this stays fixed at 'assigned'.
|
||||
const [selectedTimeField, setSelectedTimeField] = useState('assigned');
|
||||
const [selectedTimeField] = useState('assigned');
|
||||
const [timeFieldMenuOpen, setTimeFieldMenuOpen] = useState(false);
|
||||
const timeFieldMenuRef = useRef(null);
|
||||
|
||||
@@ -906,7 +877,7 @@ const Dispatch = ({
|
||||
// id/label/range/startHour/endHour just like the default list — the rest
|
||||
// of the file reads BATCHES (derived below) without caring whether the
|
||||
// values came from defaults or from operator edits.
|
||||
const [slotsConfig, setSlotsConfig] = useState(() => {
|
||||
const [slotsConfig] = useState(() => {
|
||||
if (typeof window === 'undefined') return BATCHES_DEFAULT;
|
||||
try {
|
||||
const raw = window.localStorage.getItem(SLOTS_STORAGE_KEY);
|
||||
@@ -1064,21 +1035,6 @@ const Dispatch = ({
|
||||
return match?.locationname || null;
|
||||
}, [appLocations, selectedAppLocationId]);
|
||||
|
||||
const handleLocationPick = (id) => {
|
||||
logger.info('Switching hub/location ID:', id);
|
||||
setSelectedAppLocationId(Number(id));
|
||||
setLocationMenuOpen(false);
|
||||
if (typeof window !== 'undefined') {
|
||||
try { localStorage.setItem('applocationid', String(id)); } catch (e) { /* ignore quota errors */ }
|
||||
}
|
||||
// Switching hubs invalidates the current focused rider/kitchen/zone since
|
||||
// they belong to the previous hub's data. handleRiderFocus is declared
|
||||
// further down the component but the closure is only called after click,
|
||||
// so the reference resolves cleanly.
|
||||
handleRiderFocus(null);
|
||||
setFocusedKitchen(null);
|
||||
setFocusedZone(null);
|
||||
};
|
||||
|
||||
const [osrmRoutes, setOsrmRoutes] = useState({});
|
||||
// Mirror of osrmRoutes held in a ref so fetchRoute can check the cache without
|
||||
@@ -1777,13 +1733,6 @@ const Dispatch = ({
|
||||
};
|
||||
}, [focusedRider, focusedKitchen, isAllActiveView, activeViewRiders, stats]);
|
||||
|
||||
// Count of in-progress deliveries shown in the Active view list. Derives from
|
||||
// the sticky cache (via activeViewRiders) so header and card list always agree.
|
||||
const activeDeliveryCount = useMemo(
|
||||
() => (isAllActiveView ? activeViewRiders.reduce((sum, r) => sum + r.orders.length, 0) : 0),
|
||||
[isAllActiveView, activeViewRiders]
|
||||
);
|
||||
|
||||
// List of deliveryids we want GPS logs for. Drives two pipelines:
|
||||
// • renderRoutes() — actual-route polylines on the main map for
|
||||
// every visible rider/trip
|
||||
@@ -1850,6 +1799,7 @@ const Dispatch = ({
|
||||
// _ts on each ping to compute per-step dt, so we run it BEFORE
|
||||
// stripping _ts on the way out.
|
||||
const smoothed = kalmanSmoothGps(sorted);
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
return smoothed.map(({ _ts, ...p }) => p);
|
||||
},
|
||||
// Always-on so the main map can render actual-route polylines (not just
|
||||
@@ -2787,7 +2737,7 @@ const Dispatch = ({
|
||||
? new Map(riderActualTracks.map((t) => [String(t.deliveryid), t.sequenceStep]))
|
||||
: null;
|
||||
|
||||
return ordersToRender.map((o, idx) => {
|
||||
return ordersToRender.map((o) => {
|
||||
const rid = o.rider_id;
|
||||
const active = rid ? activeRiders.has(rid) : true;
|
||||
let color = getRiderColor(rid);
|
||||
@@ -3180,13 +3130,6 @@ const Dispatch = ({
|
||||
return routes;
|
||||
};
|
||||
|
||||
const toggleRider = (rid) => {
|
||||
const newActive = new Set(activeRiders);
|
||||
if (newActive.has(rid)) newActive.delete(rid);
|
||||
else newActive.add(rid);
|
||||
setActiveRiders(newActive);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`dispatch-container${embedded ? ' embedded' : ''}${compareOpen ? ' compare-open' : ''}`}>
|
||||
{!embedded && (
|
||||
@@ -4928,15 +4871,6 @@ const Dispatch = ({
|
||||
(o) => o.deliveryid != null && String(o.deliveryid) === String(t.deliveryid)
|
||||
);
|
||||
|
||||
const statusStyle = getStatusStyle(t.orderstatus);
|
||||
const flagSvg = t.orderstatus
|
||||
? `<svg class="cmark-flag" viewBox="0 0 18 22" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="1.5" y1="0" x2="1.5" y2="22" stroke="#0f172a" stroke-width="1.6" stroke-linecap="round"/>
|
||||
<polygon points="2,1 17,1 13.5,5.5 17,10 2,10" fill="${statusStyle.bg}" stroke="#0f172a" stroke-width="0.6" stroke-linejoin="round"/>
|
||||
${isDelivered ? '<polyline points="5,5.5 7,7.5 11,3.5" fill="none" stroke="#fff" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>' : ''}
|
||||
</svg>`
|
||||
: '';
|
||||
|
||||
const dropClasses = ['compare-step-pin'];
|
||||
if (isFocusedStep) dropClasses.push('is-focused');
|
||||
if (isDelivered) dropClasses.push('is-delivered');
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import dayjs from 'dayjs';
|
||||
import { HiOutlineArrowLeft } from 'react-icons/hi';
|
||||
import { IoReload } from 'react-icons/io5';
|
||||
import { MdTwoWheeler } from 'react-icons/md';
|
||||
|
||||
import { Button } from '@astryxdesign/core/Button';
|
||||
import { IconButton } from '@astryxdesign/core/IconButton';
|
||||
@@ -12,27 +9,12 @@ import { Tooltip } from '@astryxdesign/core/Tooltip';
|
||||
import { Stack } from '@astryxdesign/core/Stack';
|
||||
import { Heading } from '@astryxdesign/core/Heading';
|
||||
|
||||
import {
|
||||
createAutomationDeliveries,
|
||||
createOptimisationDeliveries,
|
||||
finalCreatedeliveries,
|
||||
notifyRider,
|
||||
reconcileSteps
|
||||
} from '../api/api';
|
||||
import { finalCreatedeliveries, notifyRider } from '../api/api';
|
||||
import { OpenToast } from 'components/nearle_components/OpenToast';
|
||||
import CSVExport from 'components/third-party/ReactTable';
|
||||
import CircularLoader from 'components/nearle_components/CircularLoader';
|
||||
import Dispatch from './Dispatch';
|
||||
import { stepColor } from './dispatchShared';
|
||||
import { BRAND, DT } from '../_shared/ordersDesign';
|
||||
|
||||
const tuningTypes = [
|
||||
{ tuneid: 1, type: 'Balanced', value: 'balanced' },
|
||||
{ tuneid: 2, type: 'Aggressive Speed', value: 'aggressive_speed' },
|
||||
{ tuneid: 3, type: 'Fuel Saver', value: 'fuel_saver' },
|
||||
{ tuneid: 4, type: 'Zone Strict', value: 'zone_strict' }
|
||||
];
|
||||
|
||||
// Flatten the API's zoned shape into [{ rider_id, rider_name, orders }] for
|
||||
// the Reconcile tab UI and the reconcile-API payload.
|
||||
const extractRiders = (previewData) => {
|
||||
@@ -103,91 +85,6 @@ const flattenRiders = (riders) => {
|
||||
return out;
|
||||
};
|
||||
|
||||
// Merge a reconcile-API response { riders:[{rider_id, orders}] } back into
|
||||
// dispatchPreviewData. Replaces each rider's orders[] in zones (preserving
|
||||
// zone containment), then rebuilds the flat details list from the new tree.
|
||||
const applyReconcileResponse = (preview, response) => {
|
||||
if (!preview || !Array.isArray(response?.riders)) return preview;
|
||||
const next = JSON.parse(JSON.stringify(preview));
|
||||
|
||||
const newOrdersByRider = new Map(
|
||||
response.riders.map((r) => [String(r.rider_id), r.orders || []])
|
||||
);
|
||||
|
||||
if (Array.isArray(next.zones) && next.zones.length) {
|
||||
// Pass 1: wipe every existing copy of a responding rider's orders across
|
||||
// ALL zones. The server's reconciled list is the single source of truth,
|
||||
// and a rider can be present in multiple zones (one per delivery suburb).
|
||||
// The previous "update first match, delete from map" loop left stale
|
||||
// copies in the other zones, which extractRiders then concatenated into
|
||||
// duplicate orderids — surfacing as duplicate deliveries on Assign.
|
||||
next.zones.forEach((zone) => {
|
||||
if (!Array.isArray(zone.riders)) return;
|
||||
zone.riders.forEach((r) => {
|
||||
const key = String(r.rider_id ?? r.userid);
|
||||
if (newOrdersByRider.has(key)) r.orders = [];
|
||||
});
|
||||
});
|
||||
|
||||
// Pass 2: drop the reconciled orders onto the first zone that already
|
||||
// lists the rider. If the rider isn't anywhere in the tree, append a
|
||||
// fresh rider entry to zone[0].
|
||||
newOrdersByRider.forEach((orders, riderKey) => {
|
||||
let placed = false;
|
||||
for (const zone of next.zones) {
|
||||
if (!Array.isArray(zone.riders)) continue;
|
||||
const target = zone.riders.find(
|
||||
(r) => String(r.rider_id ?? r.userid) === riderKey
|
||||
);
|
||||
if (target) {
|
||||
target.orders = orders;
|
||||
placed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!placed) {
|
||||
const target = next.zones[0];
|
||||
target.riders = target.riders || [];
|
||||
target.riders.push({
|
||||
rider_id: Number(riderKey) || riderKey,
|
||||
rider_name: orders[0]?.rider_name || `Rider ${riderKey}`,
|
||||
orders
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
next.zones = [
|
||||
{
|
||||
zone_name: 'Reconciled',
|
||||
riders: response.riders.map((r) => ({
|
||||
rider_id: r.rider_id,
|
||||
rider_name: r.rider_name || `Rider ${r.rider_id}`,
|
||||
orders: r.orders || []
|
||||
}))
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
// Rebuild flat details from the updated zones->riders->orders tree.
|
||||
const flatDetails = [];
|
||||
next.zones.forEach((zone) => {
|
||||
(zone.riders || []).forEach((r) => {
|
||||
(r.orders || []).forEach((o) => {
|
||||
flatDetails.push({
|
||||
...o,
|
||||
rider_id: r.rider_id,
|
||||
userid: r.rider_id,
|
||||
rider_name: r.rider_name,
|
||||
rider: r.rider_name
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
next.details = flatDetails;
|
||||
|
||||
return next;
|
||||
};
|
||||
|
||||
const Preview = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
@@ -197,7 +94,7 @@ const Preview = () => {
|
||||
// through this state. The Dispatch tab renders from it, the Reconcile tab
|
||||
// derives its rider list from it, and Assign Orders sends a flattened copy
|
||||
// of it to the API.
|
||||
const [dispatchPreviewData, setDispatchPreviewData] = useState(stateData.dispatchPreviewData || null);
|
||||
const [dispatchPreviewData] = useState(stateData.dispatchPreviewData || null);
|
||||
|
||||
// The AI response arrives via location.state, which the browser stores in
|
||||
// history.state and persists across reloads. That means a reload of
|
||||
@@ -221,34 +118,11 @@ const Preview = () => {
|
||||
document.body.style.overflow = 'hidden';
|
||||
return () => { document.body.style.overflow = prev; };
|
||||
}, []);
|
||||
const [csvExportData, setCsvExportData] = useState([]);
|
||||
const [, setCsvExportData] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [tabValue, setTabValue] = useState(0);
|
||||
|
||||
const [reconcileLoading, setReconcileLoading] = useState(false);
|
||||
const [hasReconciled, setHasReconciled] = useState(false);
|
||||
|
||||
// Tracks riders whose orders have been edited since the last AI response
|
||||
// or successful reconcile. Only these are sent to the reconcile API — the
|
||||
// server-side step re-ordering only needs to see what actually changed.
|
||||
const [dirtyRiderIds, setDirtyRiderIds] = useState(() => new Set());
|
||||
|
||||
const aiMode = stateData.aiMode ?? 1;
|
||||
const selectedMode = stateData.selectedMode || null;
|
||||
const deliveryData = stateData.deliveryData || [];
|
||||
const autoRiders = stateData.autoRiders || [];
|
||||
const absentRidersPayload = stateData.absentRidersPayload || [];
|
||||
const rider = stateData.rider || null;
|
||||
|
||||
const appId = useMemo(() => {
|
||||
if (stateData.appId) return stateData.appId;
|
||||
if (typeof window !== 'undefined') {
|
||||
const v = localStorage.getItem('applocationid');
|
||||
return v ? Number(v) : 0;
|
||||
}
|
||||
return 0;
|
||||
}, [stateData.appId]);
|
||||
|
||||
// Derived: rider list for the Reconcile tab. Recomputes whenever the cache
|
||||
// (dispatchPreviewData) changes — so Reconcile reflects here without a separate state.
|
||||
const reconcileRiders = useMemo(() => extractRiders(dispatchPreviewData), [dispatchPreviewData]);
|
||||
@@ -293,23 +167,6 @@ const Preview = () => {
|
||||
onError: (error) => OpenToast(error.message, 'error', 2000)
|
||||
});
|
||||
|
||||
const createDeliveryMutation = useMutation({
|
||||
mutationFn: aiMode == 0 ? createOptimisationDeliveries : createAutomationDeliveries,
|
||||
onSuccess: (data) => {
|
||||
OpenToast('Orders Optimised Successfully', 'success', 2000);
|
||||
// Brand new response = brand new source of truth.
|
||||
setDispatchPreviewData(data);
|
||||
setHasReconciled(false);
|
||||
setDirtyRiderIds(new Set());
|
||||
setIsLoading(false);
|
||||
},
|
||||
onError: (error) => {
|
||||
OpenToast(error.message, 'error', 4000);
|
||||
setIsLoading(false);
|
||||
},
|
||||
onSettled: () => setIsLoading(false)
|
||||
});
|
||||
|
||||
const createFinalDeliveryMutation = useMutation({
|
||||
mutationFn: finalCreatedeliveries,
|
||||
onSuccess: () => {
|
||||
@@ -325,57 +182,6 @@ const Preview = () => {
|
||||
onSettled: () => setIsLoading(false)
|
||||
});
|
||||
|
||||
const reconcileMutation = useMutation({
|
||||
mutationFn: reconcileSteps,
|
||||
onMutate: () => setReconcileLoading(true),
|
||||
onSuccess: (data) => {
|
||||
if (Array.isArray(data?.riders)) {
|
||||
// Merge: applyReconcileResponse replaces orders for riders present
|
||||
// in the response and leaves the rest of the cache untouched.
|
||||
setDispatchPreviewData((prev) => applyReconcileResponse(prev, data));
|
||||
setHasReconciled(true);
|
||||
// Clear only the riders we just reconciled from the dirty set, so
|
||||
// any unrelated edits made meanwhile are preserved.
|
||||
setDirtyRiderIds((prev) => {
|
||||
const next = new Set(prev);
|
||||
data.riders.forEach((r) => next.delete(String(r.rider_id)));
|
||||
return next;
|
||||
});
|
||||
OpenToast('Steps reconciled — preview updated', 'success', 2000);
|
||||
} else {
|
||||
OpenToast('Reconcile returned no rider data', 'warning', 3000);
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
OpenToast(error.message || 'Reconcile failed', 'error', 4000);
|
||||
},
|
||||
onSettled: () => setReconcileLoading(false)
|
||||
});
|
||||
|
||||
const handleCreateDelivery = (tune) => {
|
||||
setIsLoading(true);
|
||||
if (aiMode == 0) {
|
||||
createDeliveryMutation.mutate({ deliveries: deliveryData });
|
||||
} else if (selectedMode && selectedMode?.value == 1) {
|
||||
createDeliveryMutation.mutate({
|
||||
deliveries: deliveryData,
|
||||
hypertuning_params: tune || null,
|
||||
selectedMode,
|
||||
absent_riders: absentRidersPayload
|
||||
});
|
||||
} else {
|
||||
createDeliveryMutation.mutate({
|
||||
data: {
|
||||
orders: deliveryData,
|
||||
riders: autoRiders,
|
||||
config: { pay_type: 'hourly', base_pay: 300.0, strategy: 'multi_trip' },
|
||||
absent_riders: absentRidersPayload
|
||||
},
|
||||
selectedMode
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleFinalCreateDelivery = () => {
|
||||
if (!finaldeliveryList?.length) {
|
||||
OpenToast('No deliveries to assign', 'error', 3000);
|
||||
@@ -385,29 +191,6 @@ const Preview = () => {
|
||||
createFinalDeliveryMutation.mutate({ deliveries: finaldeliveryList });
|
||||
};
|
||||
|
||||
const handleReconcile = () => {
|
||||
if (!reconcileRiders.length) {
|
||||
OpenToast('No riders to reconcile', 'warning', 3000);
|
||||
return;
|
||||
}
|
||||
// Only send riders that were edited since the last AI response / reconcile.
|
||||
// Their step ordering is the only thing that can be stale — untouched
|
||||
// riders are skipped to keep the payload small.
|
||||
const dirty = reconcileRiders.filter((r) =>
|
||||
dirtyRiderIds.has(String(r.rider_id))
|
||||
);
|
||||
if (!dirty.length) {
|
||||
OpenToast('No edits to reconcile', 'info', 2500);
|
||||
return;
|
||||
}
|
||||
reconcileMutation.mutate({
|
||||
riders: dirty.map((r) => ({
|
||||
rider_id: r.rider_id,
|
||||
orders: r.orders
|
||||
}))
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="dispatch-preview-shell"
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useLocation } from 'react-router-dom';
|
||||
import logo_nearle1 from '../../../assets/images/doormile-mark.png';
|
||||
import axios from 'axios';
|
||||
import dayjs from 'dayjs';
|
||||
import Loader from 'components/Loader';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { PrinterFilled } from '@ant-design/icons';
|
||||
import { useReactToPrint } from 'react-to-print';
|
||||
@@ -49,7 +48,6 @@ const InvoicePreview = () => {
|
||||
logger.info('previewSelect', location.state);
|
||||
const componentRef = useRef(null);
|
||||
const handlePrint = useReactToPrint({ contentRef: componentRef });
|
||||
const [tabletype, settabletype] = useState(true);
|
||||
const [paydialog, setpaydialog] = useState(false);
|
||||
const [refnumber, setRefnumber] = useState('');
|
||||
const [remarks, setRemarks] = useState('');
|
||||
|
||||
@@ -66,9 +66,9 @@ const ResponsiveLocationDrawer = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [page, setPage] = React.useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = React.useState(10);
|
||||
const [pageCount, setPageCount] = React.useState(0);
|
||||
const [startdate, setStartdate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const [enddate, setEnddate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const [, setPageCount] = React.useState(0);
|
||||
const [startdate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const [enddate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const [searchLocation, setSearchLocation] = useState('');
|
||||
const [debouncedSearchLocation, setDebouncedSearchLocation] = useState('');
|
||||
|
||||
@@ -137,9 +137,7 @@ const ResponsiveLocationDrawer = () => {
|
||||
data: ordersData,
|
||||
fetchNextPage,
|
||||
hasNextPage,
|
||||
isFetchingNextPage,
|
||||
isLoading,
|
||||
error
|
||||
isFetchingNextPage
|
||||
} = useInfiniteQuery({
|
||||
queryKey: [
|
||||
'orders',
|
||||
|
||||
@@ -229,14 +229,6 @@ const OrdersPreview = () => {
|
||||
enabled: appId !== 0 // Ensures query runs only when appId is valid
|
||||
});
|
||||
|
||||
const getRiderName = async (userid) => {
|
||||
await ridersList.map((rider) => {
|
||||
if (rider.userid == userid) {
|
||||
return rider.firstname;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const paymentOptions = useMemo(
|
||||
() => (paymentModes || []).map((v) => ({ value: String(v.apptypeid), label: v.label })),
|
||||
[paymentModes]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { useEffect, useState, useRef, Fragment } from 'react';
|
||||
import { useEffect, useMemo, useState, useRef, Fragment } from 'react';
|
||||
import { calculateDrivingDistance, calculateTotalCharge } from '../../../utils/distance';
|
||||
import { createAddressSearchSource } from '../../../utils/addressSearch';
|
||||
import { FaPhoneAlt } from 'react-icons/fa';
|
||||
import { GiDoorHandle } from 'react-icons/gi';
|
||||
import { FaLandmarkDome } from 'react-icons/fa6';
|
||||
@@ -9,9 +10,7 @@ import { MdLocationCity } from 'react-icons/md';
|
||||
import { TbMapPinCode } from 'react-icons/tb';
|
||||
import { FaLocationDot } from 'react-icons/fa6';
|
||||
import axios from 'axios';
|
||||
import Geocode from 'react-geocode';
|
||||
import Loader from 'components/Loader';
|
||||
import * as geolib from 'geolib';
|
||||
import { FaUser } from 'react-icons/fa6';
|
||||
import dayjs from 'dayjs';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
@@ -27,6 +26,7 @@ import logger from 'utils/logger';
|
||||
// — this mirrors the "plain CSS grid" fallback already used by the sibling
|
||||
// createCustomer.js `FieldGrid` helper.
|
||||
import { TextInput } from '@astryxdesign/core/TextInput';
|
||||
import { Typeahead } from '@astryxdesign/core/Typeahead';
|
||||
import { CheckboxInput } from '@astryxdesign/core/CheckboxInput';
|
||||
import { NumberInput } from '@astryxdesign/core/NumberInput';
|
||||
import { TextArea } from '@astryxdesign/core/TextArea';
|
||||
@@ -58,10 +58,10 @@ import {
|
||||
|
||||
// ============================================================================
|
||||
// Plain-CSS layout shims — Astryx has no Grid/Stack/Box/Typography/Paper
|
||||
// equivalents, so these small local helpers (not @mui) stand in for the MUI
|
||||
// equivalents, so these small local helpers stand in for the
|
||||
// layout primitives previously used here, translating the same `sx`-shaped
|
||||
// spacing shorthand (p/m/gap/borderRadius are ×8px steps, bgcolor→
|
||||
// backgroundColor) into real inline CSS. MUI pseudo-selector keys (e.g.
|
||||
// backgroundColor) into real inline CSS. Pseudo-selector keys (e.g.
|
||||
// `'&:hover'`) are not representable inline and are dropped.
|
||||
// ============================================================================
|
||||
const SPACING_KEYS = {
|
||||
@@ -306,52 +306,58 @@ const SectionCard = ({ children, sx = {} }) => (
|
||||
</Paper>
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
// Parses a `toPlace`-shaped `address_components` array (see utils/addressSearch)
|
||||
// into the flat field set both the pickup and drop handlers below persist.
|
||||
const parseAddressComponents = (place) => {
|
||||
const address = {
|
||||
address: `${place.name} ${place.formatted_address}`,
|
||||
street_number: '',
|
||||
route: '',
|
||||
locality: '',
|
||||
sublocality_level_1: '',
|
||||
administrative_area_level_3: '',
|
||||
administrative_area_level_1: '',
|
||||
country: '',
|
||||
postal_code: ''
|
||||
};
|
||||
place.address_components.forEach((component) => {
|
||||
component.types.forEach((type) => {
|
||||
switch (type) {
|
||||
case 'street_number':
|
||||
address.street_number = component.long_name;
|
||||
break;
|
||||
case 'route':
|
||||
address.route = component.long_name;
|
||||
break;
|
||||
case 'locality':
|
||||
address.locality = component.long_name;
|
||||
break;
|
||||
case 'sublocality_level_1':
|
||||
address.sublocality_level_1 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_3':
|
||||
address.administrative_area_level_3 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_1':
|
||||
address.administrative_area_level_1 = component.long_name;
|
||||
break;
|
||||
case 'country':
|
||||
address.country = component.long_name;
|
||||
break;
|
||||
case 'postal_code':
|
||||
address.postal_code = component.long_name;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
return address;
|
||||
};
|
||||
|
||||
const Createorder1 = () => {
|
||||
Geocode.setApiKey(process.env.REACT_APP_GOOGLE_MAPS_API_KEY);
|
||||
// ================================================= || GoogleMaps (Drawer) || =================================================
|
||||
const [value, setValue] = React.useState(null);
|
||||
const [value1, setValue1] = React.useState(null);
|
||||
const [inputValue, setInputValue] = React.useState('');
|
||||
const [inputValue1, setInputValue1] = React.useState('');
|
||||
const [inputValue2, setInputValue2] = React.useState('');
|
||||
const [inputValue3, setInputValue3] = React.useState('');
|
||||
const [options, setOptions] = React.useState([]);
|
||||
const [options1, setOptions1] = React.useState([]);
|
||||
const loaded = React.useRef(false);
|
||||
const loaded1 = React.useRef(false);
|
||||
const [mobilenumber, setMobilenumber] = useState('');
|
||||
const [emailaddress, setEmailaddress] = useState('');
|
||||
const [city, setCity] = useState('');
|
||||
const [city1, setCity1] = useState('');
|
||||
const [zipcode, setZipcode] = useState('');
|
||||
const [zipcode1, setZipcode1] = useState('');
|
||||
const [state, setState] = useState('');
|
||||
const [state1, setState1] = useState('');
|
||||
const [suburb, setSuburb] = useState('');
|
||||
const [suburb1, setSuburb1] = useState('');
|
||||
const [pickContactName, setPickContactName] = useState('');
|
||||
const [dropContactName, setDropContactName] = useState('');
|
||||
const [pickdoorno, setPickDoorno] = useState('');
|
||||
const [dropDoorno, setDropDoorno] = useState('');
|
||||
const [pickLandmark, setPickLandmark] = useState('');
|
||||
const [dropLandmark, setDropLandmark] = useState('');
|
||||
const [address, setAddress] = useState('');
|
||||
const [address1, setAddress1] = useState('');
|
||||
const [latlong, setLatlong] = useState({});
|
||||
const [latlong1, setLatlong1] = useState({});
|
||||
const autocompleteService = useRef(null);
|
||||
const [pickPlace, setPickPlace] = useState(null);
|
||||
const [dropPlace, setDropPlace] = useState(null);
|
||||
const [tenanatLocoId, setTenanatLocoId] = useState(localStorage.getItem('locationid'));
|
||||
const [isLocation, setIsLocation] = useState(false);
|
||||
const textFieldRef1 = useRef(null);
|
||||
@@ -359,296 +365,30 @@ const Createorder1 = () => {
|
||||
const [collectionamt, setCollectionamt] = useState(0);
|
||||
const [quantity, setQuantity] = useState(1);
|
||||
|
||||
const handleOkClick1 = () => {
|
||||
// Set focus back to the text field after clicking the "OK" chip
|
||||
if (textFieldRef1.current) {
|
||||
textFieldRef1.current.focus();
|
||||
}
|
||||
};
|
||||
|
||||
const handleOkClick2 = () => {
|
||||
// Set focus back to the text field after clicking the "OK" chip
|
||||
if (textFieldRef2.current) {
|
||||
textFieldRef2.current.focus();
|
||||
}
|
||||
};
|
||||
|
||||
const top100Films = [
|
||||
{ label: 'The Shawshank Redemption', year: 1994 },
|
||||
{ label: 'The Godfather', year: 1972 },
|
||||
{ label: 'The Godfather: Part II', year: 1974 },
|
||||
{ label: 'The Dark Knight', year: 2008 },
|
||||
{ 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;
|
||||
// logger.info({ lat, lng });
|
||||
// setLatlong({
|
||||
// lat,
|
||||
// lng
|
||||
// });
|
||||
// logger.info(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 || '');
|
||||
// logger.info({ 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) => {
|
||||
// logger.info(error);
|
||||
// }
|
||||
// );
|
||||
// } catch (err) {
|
||||
// logger.error(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
|
||||
// });
|
||||
// logger.info(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 || '');
|
||||
// logger.info({ 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) => {
|
||||
// logger.info(error);
|
||||
// }
|
||||
// );
|
||||
// } catch (err) {
|
||||
// logger.error(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 navigate = useNavigate();
|
||||
const [open, setOpen] = useState({});
|
||||
const [open1, setOpen1] = useState('');
|
||||
const [open2, setOpen2] = useState(false);
|
||||
const [open3, setOpen3] = useState(false);
|
||||
const [open4, setOpen4] = useState(false);
|
||||
const [shift, setShift] = useState(1);
|
||||
const [clientlist, setClientlist] = useState([]);
|
||||
const [clientdetail, setClientdetail] = useState([]);
|
||||
const [eventname, setEventname] = useState('');
|
||||
const [startdate, setStartdate] = useState(dayjs().format('MM-DD-YYYY'));
|
||||
const [enddate, setEnddate] = useState(dayjs().add(1, 'day').format('MM-DD-YYYY'));
|
||||
const [, setEnddate] = useState(dayjs().add(1, 'day').format('MM-DD-YYYY'));
|
||||
// const [starttime, setStatrttime] = useState(`${dayjs().format('MM-DD-YYYY')} 08:00:00`);
|
||||
const [starttime, setStatrttime] = useState();
|
||||
// const [endtime, setEndtime] = useState(`${dayjs().format('MM-DD-YYYY')} 20:00:00`);
|
||||
const [endtime, setEndtime] = useState();
|
||||
const [timeslotarr, setTimeslotarr] = useState([]);
|
||||
const [currentsno, setCurrentsno] = useState('');
|
||||
const [roleoptions, setRoleoptions] = useState([]);
|
||||
const [otherinstructions, setOtherinstructions] = useState('');
|
||||
const [attireslist, setAttireslist] = useState([]);
|
||||
const [serviceaddonslist, setServiceaddonslist] = useState([]);
|
||||
const [orderaddonobj, setOrderaddonobj] = useState([]);
|
||||
const [stafflist, setStafflist] = useState([]);
|
||||
const [loading2, setLoading2] = useState(false);
|
||||
const [, setLoading2] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [btnLoading, setBtnLoading] = useState(false);
|
||||
const [shiftarr, setShiftarr] = useState([]);
|
||||
const [shiftarr1, setShiftarr1] = useState([]);
|
||||
const [orderarr, setOrderarr] = useState([]);
|
||||
const [shiftarr] = useState([]);
|
||||
const [, setOrderarr] = useState([]);
|
||||
const [alertmessage, setAlertmessage] = useState('');
|
||||
const [tabstatus, setTabstatus] = useState('');
|
||||
const [tenantinfo, setTenantinfo] = useState({});
|
||||
const [searchword, setSearchword] = useState('');
|
||||
const [clientdetailarr, setClientdetailarr] = useState([]);
|
||||
const [clientdetailbusinessarr, setClientdetailbusinessarr] = useState([]);
|
||||
const [searchword] = useState('');
|
||||
const [, setClientdetailarr] = useState([]);
|
||||
const [admintoken, setAdmintoken] = useState();
|
||||
const [tenantlocationlist, setTenantlocationlist] = useState([]);
|
||||
const [tenant, setTenant] = useState({});
|
||||
const [clientinfo, setClientinfo] = useState({});
|
||||
const [selectedtime, setSelectedtime] = useState('');
|
||||
const [tenantlist, setTenantlist] = useState([]);
|
||||
const [tenantid, setTenantid] = useState();
|
||||
const [tenantlocation, setTenantlocation] = useState('');
|
||||
const [pickupswitch, setPickupswitch] = useState(true);
|
||||
const [deliverytype, setDeliverytype] = useState('B');
|
||||
const [dropswitch, setDropswitch] = useState(false);
|
||||
const [, setTenantid] = useState();
|
||||
const [startPoint, setStartPoint] = useState({ latitude: 0, longitude: 0 });
|
||||
const [endPoint, setEndPoint] = useState({ latitude: 0, longitude: 0 });
|
||||
const [showDistance, setShowDistance] = useState(false);
|
||||
@@ -660,7 +400,7 @@ const Createorder1 = () => {
|
||||
const [subCat, setSubCat] = useState([]);
|
||||
const [subCatName, setSubCatName] = useState('Select ');
|
||||
const [subCatId, setSubCatId] = useState();
|
||||
const [weight, setWeight] = useState('');
|
||||
const [, setWeight] = useState('');
|
||||
const tid = localStorage.getItem('tenantid');
|
||||
const [selectedCatChip, setSelectedCatChip] = useState(null);
|
||||
const [isCustomerOpen, setIsCustomerOpen] = useState(false);
|
||||
@@ -717,26 +457,6 @@ const Createorder1 = () => {
|
||||
}
|
||||
}, [startPoint, endPoint]);
|
||||
|
||||
const getDistance = () => {
|
||||
const dist = geolib.getPreciseDistance(startPoint, endPoint, 1);
|
||||
logger.info(`Distance: ${dist} meters`);
|
||||
const distanceInKm = (dist / 1000).toFixed(2);
|
||||
const roundedDistance = Math.round(distanceInKm);
|
||||
logger.info('roundedDistance', roundedDistance);
|
||||
setDistance(roundedDistance.toFixed(2));
|
||||
if (roundedDistance < minKm) {
|
||||
setTotalCharge(basePrice);
|
||||
} else {
|
||||
const total = (roundedDistance - minKm) * pricePerKm + basePrice;
|
||||
setTotalCharge(total);
|
||||
}
|
||||
setShowDistance(true);
|
||||
if (roundedDistance > appLocaRadius) {
|
||||
setShowDistance(true);
|
||||
setOpen4(true);
|
||||
}
|
||||
};
|
||||
|
||||
const calculateDistance = async (pickup, drop) => {
|
||||
try {
|
||||
const roundedDistance = await calculateDrivingDistance(pickup, drop);
|
||||
@@ -805,42 +525,6 @@ const Createorder1 = () => {
|
||||
}
|
||||
}, [searchword]);
|
||||
|
||||
// const { ref: materialRef } = usePlacesWidget({
|
||||
// apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
|
||||
// onPlaceSelected: (place) => {
|
||||
// logger.info(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 || ====================================================
|
||||
const fetchtenantinfo = async () => {
|
||||
setLoading(true);
|
||||
@@ -904,9 +588,9 @@ const Createorder1 = () => {
|
||||
logger.info('endtime', `${dayjs().format('MM-DD-YYYY')} ${closetime} `);
|
||||
let arr = [];
|
||||
for (
|
||||
let i = `${dayjs().format('MM-DD-YYYY')} ${opentime}`, j = 0;
|
||||
let i = `${dayjs().format('MM-DD-YYYY')} ${opentime}`;
|
||||
dayjs(`${dayjs().format('MM-DD-YYYY')} ${closetime} `).diff(i, 'm') >= 0;
|
||||
j++, i = dayjs(i).add(30, 'm')
|
||||
i = dayjs(i).add(30, 'm')
|
||||
) {
|
||||
arr.push(i);
|
||||
}
|
||||
@@ -961,14 +645,6 @@ const Createorder1 = () => {
|
||||
logger.info(alertmessage);
|
||||
};
|
||||
|
||||
function closeAddressModal() {
|
||||
setOpen2(false);
|
||||
}
|
||||
function closetimemodal() {
|
||||
setOpen3(false);
|
||||
setCurrentsno('');
|
||||
}
|
||||
|
||||
// =============================================== || createsubmitobj1 (create orders) || ===============================================
|
||||
|
||||
const createsubmitobj2 = async () => {
|
||||
@@ -1149,17 +825,6 @@ const Createorder1 = () => {
|
||||
logger.info(shiftarr);
|
||||
}, [shiftarr]);
|
||||
|
||||
const clicked1 = (e) => {
|
||||
setShift(e);
|
||||
};
|
||||
|
||||
const dialogopen = (i, result) => {
|
||||
logger.info(i, result);
|
||||
setOpen({ shiftsno: result.sno, sno: i.sno });
|
||||
};
|
||||
const dialogclose = () => {
|
||||
setOpen('');
|
||||
};
|
||||
// ========================================================= || clientdetails || =========================================================
|
||||
const clientdetails = async () => {
|
||||
setLoading2(true);
|
||||
@@ -1207,248 +872,18 @@ const Createorder1 = () => {
|
||||
clientdetails();
|
||||
// clientdetailsbusiness();
|
||||
}, [searchCustList.length > 3, searchCustList == '']);
|
||||
// ========================================================= || clientdetailsbusiness || =========================================================
|
||||
const clientdetailsbusiness = async () => {
|
||||
setLoading2(true);
|
||||
try {
|
||||
await axios
|
||||
.get(`${process.env.REACT_APP_URL}/customers/getbytid/?tenantid=${tid}&locationid=1`)
|
||||
.then((res) => {
|
||||
logger.info('clientdetailsbusiness', res.data.details);
|
||||
if (res.data.status) {
|
||||
setClientdetail(res.data.details);
|
||||
// if (!searchword) {
|
||||
// setClientdetailarr(res.data.details)
|
||||
// }
|
||||
let arr = [];
|
||||
res.data.details.map((val) => {
|
||||
arr.push({
|
||||
label: `${val.firstname} | ${val.contactno}`,
|
||||
...val
|
||||
});
|
||||
});
|
||||
setClientdetailbusinessarr(arr);
|
||||
}
|
||||
setLoading2(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(err);
|
||||
setLoading2(false);
|
||||
opentoast('server error', 'warning');
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
setLoading2(false);
|
||||
}
|
||||
};
|
||||
|
||||
// ================================================== || 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) => {
|
||||
logger.info(res);
|
||||
if (res.data.message == 'Success') {
|
||||
enqueueSnackbar('Notification sent Successfully', {
|
||||
variant: 'success',
|
||||
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
||||
autoHideDuration: 1000
|
||||
});
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(err);
|
||||
enqueueSnackbar(err.message, {
|
||||
variant: 'error',
|
||||
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
||||
autoHideDuration: 1000
|
||||
});
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
// ============================================= || Google Maps Autocomplete(pick) || =============================================
|
||||
useEffect(() => {
|
||||
// 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}`);
|
||||
logger.info('new place', place); // Do something with the selected place
|
||||
logger.info(' pick (new place) lat lng', { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }); // Do something with the selected place
|
||||
// to trigger getDistance
|
||||
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}` });
|
||||
const address = {
|
||||
address: `${place.name} ${place.formatted_address}`,
|
||||
street_number: '',
|
||||
route: '',
|
||||
locality: '',
|
||||
sublocality_level_1: '',
|
||||
administrative_area_level_3: '',
|
||||
administrative_area_level_1: '',
|
||||
country: '',
|
||||
postal_code: ''
|
||||
};
|
||||
place.address_components.forEach((component) => {
|
||||
component.types.forEach((type) => {
|
||||
switch (type) {
|
||||
case 'street_number':
|
||||
address.street_number = component.long_name;
|
||||
break;
|
||||
case 'route':
|
||||
address.route = component.long_name;
|
||||
break;
|
||||
case 'locality':
|
||||
address.locality = component.long_name;
|
||||
break;
|
||||
case 'sublocality_level_1':
|
||||
address.sublocality_level_1 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_3':
|
||||
address.administrative_area_level_3 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_1':
|
||||
address.administrative_area_level_1 = component.long_name;
|
||||
break;
|
||||
case 'country':
|
||||
address.country = component.long_name;
|
||||
break;
|
||||
case 'postal_code':
|
||||
address.postal_code = component.long_name;
|
||||
break;
|
||||
// Add more cases as needed for other types
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Use address object as per your requirements
|
||||
setPickCust({
|
||||
...pickCust,
|
||||
address: address.address,
|
||||
doorno: `${address.street_number} ${address.route}`,
|
||||
suburb: address.sublocality_level_1,
|
||||
city: address.locality,
|
||||
postcode: address.postal_code,
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
logger.info('Pick Address:', address);
|
||||
});
|
||||
}
|
||||
}, [inputValue2]);
|
||||
// ============================================= || Google Maps Autocomplete(Drop) || =============================================
|
||||
|
||||
useEffect(() => {
|
||||
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}`);
|
||||
logger.info('new place', place); // Do something with the selected place
|
||||
logger.info('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() });
|
||||
setValue1(place);
|
||||
setAddress1(`${place.name} ${place.formatted_address}`);
|
||||
setDropCust({ ...dropCust, address: `${place.name} ${place.formatted_address}` });
|
||||
const address = {
|
||||
address: `${place.name} ${place.formatted_address}`,
|
||||
street_number: '',
|
||||
route: '',
|
||||
locality: '',
|
||||
sublocality_level_1: '',
|
||||
administrative_area_level_3: '',
|
||||
administrative_area_level_1: '',
|
||||
country: '',
|
||||
postal_code: ''
|
||||
};
|
||||
place.address_components.forEach((component) => {
|
||||
component.types.forEach((type) => {
|
||||
switch (type) {
|
||||
case 'street_number':
|
||||
address.street_number = component.long_name;
|
||||
break;
|
||||
case 'route':
|
||||
address.route = component.long_name;
|
||||
break;
|
||||
case 'locality':
|
||||
address.locality = component.long_name;
|
||||
break;
|
||||
case 'sublocality_level_1':
|
||||
address.sublocality_level_1 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_3':
|
||||
address.administrative_area_level_3 = component.long_name;
|
||||
break;
|
||||
case 'administrative_area_level_1':
|
||||
address.administrative_area_level_1 = component.long_name;
|
||||
break;
|
||||
case 'country':
|
||||
address.country = component.long_name;
|
||||
break;
|
||||
case 'postal_code':
|
||||
address.postal_code = component.long_name;
|
||||
break;
|
||||
// Add more cases as needed for other types
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Use address object as per your requirements
|
||||
setDropCust({
|
||||
...dropCust,
|
||||
address: address.address,
|
||||
doorno: `${address.street_number} ${address.route}`,
|
||||
suburb: address.sublocality_level_1,
|
||||
city: address.locality,
|
||||
postcode: address.postal_code,
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
logger.info('Drop Address:', address);
|
||||
});
|
||||
}
|
||||
}, [inputValue3]);
|
||||
// ============================================= || Address search (pick/drop) || =============================================
|
||||
// Nominatim search sources, soft-biased toward the operator's zone once
|
||||
// fetchTiming() resolves appLocaLat/appLocaLng — replaces the Google Places
|
||||
// Autocomplete bound to #addressAuto1 / #addressAuto2.
|
||||
const pickAddressSource = useMemo(
|
||||
() => createAddressSearchSource({ bias: { lat: appLocaLat, lng: appLocaLng } }),
|
||||
[appLocaLat, appLocaLng]
|
||||
);
|
||||
const dropAddressSource = useMemo(
|
||||
() => createAddressSearchSource({ bias: { lat: appLocaLat, lng: appLocaLng } }),
|
||||
[appLocaLat, appLocaLng]
|
||||
);
|
||||
|
||||
// ============================================= || gettenantlocations (branches) || =============================================
|
||||
const gettenantlocations = async () => {
|
||||
@@ -1611,7 +1046,7 @@ const Createorder1 = () => {
|
||||
setIsCustomerOpen(true);
|
||||
setpickordrop(1);
|
||||
setPickCust({});
|
||||
setInputValue2('');
|
||||
setPickPlace(null);
|
||||
setSearchCustList('');
|
||||
}
|
||||
}}
|
||||
@@ -1676,16 +1111,19 @@ const Createorder1 = () => {
|
||||
<Stack spacing={1.25} sx={{ mt: 0 }}>
|
||||
{addId1 == 0 ? (
|
||||
<div>
|
||||
<TextInput
|
||||
<Typeahead
|
||||
label="Address"
|
||||
isLabelHidden
|
||||
isDisabled={!isLocation}
|
||||
id="addressAuto1"
|
||||
width="100%"
|
||||
hasClear
|
||||
value={inputValue2}
|
||||
onChange={(value) => {
|
||||
setInputValue2(value);
|
||||
if (value === '') {
|
||||
width="100%"
|
||||
placeholder="Search address"
|
||||
debounceMs={500}
|
||||
searchSource={pickAddressSource}
|
||||
value={pickPlace}
|
||||
onChange={(item) => {
|
||||
setPickPlace(item);
|
||||
if (!item) {
|
||||
setPickCust({
|
||||
...pickCust,
|
||||
doorno: '',
|
||||
@@ -1696,7 +1134,29 @@ const Createorder1 = () => {
|
||||
});
|
||||
setShowDistance(false);
|
||||
setStartPoint({ latitude: 0, longitude: 0 });
|
||||
return;
|
||||
}
|
||||
const place = item.auxiliaryData;
|
||||
logger.info('pick (new place) lat lng', {
|
||||
lat: place.geometry.location.lat(),
|
||||
lng: place.geometry.location.lng()
|
||||
});
|
||||
setStartPoint({
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
const address = parseAddressComponents(place);
|
||||
setPickCust({
|
||||
...pickCust,
|
||||
address: address.address,
|
||||
doorno: `${address.street_number} ${address.route}`,
|
||||
suburb: address.sublocality_level_1,
|
||||
city: address.locality,
|
||||
postcode: address.postal_code,
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
logger.info('Pick Address:', address);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -1824,7 +1284,7 @@ const Createorder1 = () => {
|
||||
} else {
|
||||
setIsCustomerOpen(true);
|
||||
setpickordrop(2);
|
||||
setInputValue3('');
|
||||
setDropPlace(null);
|
||||
setSearchCustList('');
|
||||
}
|
||||
}}
|
||||
@@ -1953,16 +1413,19 @@ const Createorder1 = () => {
|
||||
<Stack spacing={1.25} sx={{ mt: 0 }}>
|
||||
{addId2 == 0 ? (
|
||||
<div>
|
||||
<TextInput
|
||||
id="addressAuto2"
|
||||
<Typeahead
|
||||
isDisabled={!isLocation}
|
||||
label="Address"
|
||||
width="100%"
|
||||
isLabelHidden
|
||||
hasClear
|
||||
value={inputValue3}
|
||||
onChange={(value) => {
|
||||
setInputValue3(value);
|
||||
if (value === '') {
|
||||
width="100%"
|
||||
placeholder="Search address"
|
||||
debounceMs={500}
|
||||
searchSource={dropAddressSource}
|
||||
value={dropPlace}
|
||||
onChange={(item) => {
|
||||
setDropPlace(item);
|
||||
if (!item) {
|
||||
setDropCust({
|
||||
...dropCust,
|
||||
doorno: '',
|
||||
@@ -1973,7 +1436,29 @@ const Createorder1 = () => {
|
||||
});
|
||||
setShowDistance(false);
|
||||
setEndPoint({ latitude: 0, longitude: 0 });
|
||||
return;
|
||||
}
|
||||
const place = item.auxiliaryData;
|
||||
logger.info('drop (new place) lat lng', {
|
||||
lat: place.geometry.location.lat(),
|
||||
lng: place.geometry.location.lng()
|
||||
});
|
||||
setEndPoint({
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
const address = parseAddressComponents(place);
|
||||
setDropCust({
|
||||
...dropCust,
|
||||
address: address.address,
|
||||
doorno: `${address.street_number} ${address.route}`,
|
||||
suburb: address.sublocality_level_1,
|
||||
city: address.locality,
|
||||
postcode: address.postal_code,
|
||||
latitude: place.geometry.location.lat(),
|
||||
longitude: place.geometry.location.lng()
|
||||
});
|
||||
logger.info('Drop Address:', address);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -241,7 +241,7 @@ const Details = () => {
|
||||
const [tenantaddress, setTenantaddress] = useState('');
|
||||
const [dialogopen, setDialogopen] = useState(false);
|
||||
const [orderstatus, setOrderstatus] = useState('');
|
||||
const [currentrole, setCurrentrole] = useState('');
|
||||
const [currentrole] = useState('');
|
||||
const [taxamount, setTaxamount] = useState('');
|
||||
const [subtotal, setSubtotal] = useState('');
|
||||
const [grandtotal, setGrandtotal] = useState('');
|
||||
@@ -253,13 +253,13 @@ const Details = () => {
|
||||
const [staffarr, setStaffarr] = useState([]);
|
||||
const [orderheaderid, setOrderheaderid] = useState('');
|
||||
const [tenantid, setTenantid] = useState('');
|
||||
const [starttime, setStarttime] = useState('');
|
||||
const [endtime, setEndtime] = useState('');
|
||||
const [starttime] = useState('');
|
||||
const [endtime] = useState('');
|
||||
// const [orderstatus,setOrderstatus]=useStatus('');
|
||||
const [pendingtime, setPendingtime] = useState('');
|
||||
// const [processdate,setProcessdate]=useState('');
|
||||
const [orderdetailid, setOrderdetailid] = useState('');
|
||||
const [productid, setProductid] = useState('');
|
||||
const [orderdetailid] = useState('');
|
||||
const [productid] = useState('');
|
||||
const [categoryarr, setcategoryarr] = useState([])
|
||||
const [currentshiftobj, setCurrentshiftobj] = useState({
|
||||
shifts: 0,
|
||||
@@ -268,7 +268,7 @@ const Details = () => {
|
||||
shiftid: 0,
|
||||
price: 0
|
||||
});
|
||||
const [tabstatus, setTabstatus] = useState(0)
|
||||
const [, setTabstatus] = useState(0)
|
||||
const { state } = useLocation();
|
||||
const [assignedpendingcount, setAssignedpendingcount] = useState('');
|
||||
// const [, forceUpdate] = useReducer(x => x + 1, 0);
|
||||
@@ -409,48 +409,6 @@ const Details = () => {
|
||||
});
|
||||
}
|
||||
|
||||
const fetchroleslist = async (cid, starttime1, endtime1, hid, sid) => {
|
||||
let fromdate = dayjs(starttime1).subtract(59, 'minutes')
|
||||
.format('YYYY-MM-DD HH:mm:ss');
|
||||
// let todate = dayjs(endtime1).utc().format('YYYY-MM-DD HH:mm:ss');
|
||||
// let fromdate = dayjs(starttime1).utc().format('YYYY-MM-DD HH:mm:ss');
|
||||
let todate = dayjs(endtime1)
|
||||
.format('YYYY-MM-DD HH:mm:ss');
|
||||
let url1;
|
||||
if (starttime1) {
|
||||
url1 = `${process.env.REACT_APP_URL2}/staffs/pools/getstaffs/?categoryid=${cid}&headerid=${hid}&shiftid=${sid}&starttime=${fromdate}&endtime=${todate}`;
|
||||
} else {
|
||||
url1 = `${process.env.REACT_APP_URL2}/staffs/pools/getstaffs/?categoryid=${cid}&headerid=${hid}&shiftid=${sid}`
|
||||
}
|
||||
setLoading(true);
|
||||
setStafflist([])
|
||||
await axios
|
||||
// .get(`${process.env.REACT_APP_URL2}/staffs/pools/getstaffs/?categoryid=${cid}&headerid=${hid}&starttime=${fromdate}&endtime=${todate}`)
|
||||
.get(url1)
|
||||
.then((res) => {
|
||||
logger.info('rolelist');
|
||||
logger.info(res);
|
||||
// logger.info(fromdate, todate)
|
||||
// logger.info(dayjs(starttime1).format('YYYY-MM-DD HH:mm:ss'))
|
||||
// logger.info(dayjs(endtime1).format('HH:mm:ss'))
|
||||
|
||||
|
||||
setStafflist(res.data.Details || [])
|
||||
// let result = res.data.Details.find((res1) => res1.orderheaderid == searchParams.get('id'))
|
||||
// orderheaderid
|
||||
// logger.info(result)
|
||||
// setOrderaddons(result.orderaddons);
|
||||
// setVenuetype(result.venuetype)
|
||||
// setOtherinstructions(result.remarks)
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(err);
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const fetchstafflist = async (odid) => {
|
||||
setLoading(true)
|
||||
try {
|
||||
@@ -789,88 +747,6 @@ const Details = () => {
|
||||
|
||||
}
|
||||
|
||||
const fetchassignedstaffs = async () => {
|
||||
|
||||
// logger.info(obj1)
|
||||
await axios.get(`${process.env.REACT_APP_URL2}/orders/getnotificationusers?orderheaderid=${orderheaderid}`)
|
||||
.then((res) => {
|
||||
if (res.data.status) {
|
||||
let arr1 = [];
|
||||
let data2;
|
||||
let tokenarr = []
|
||||
logger.info(res)
|
||||
|
||||
res.data.details.map((val) => {
|
||||
arr1.push({
|
||||
"notificationid": 0,
|
||||
"notificationdate": dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
"Title": "Staff Asigned",
|
||||
"message": `${val.staffname} has been assigned to the order ${orderid}`,
|
||||
"configid": 2,
|
||||
"tenantid": tenantid,
|
||||
"orderheaderid": orderheaderid,
|
||||
"orderprocessid": val.orderprocessid,
|
||||
"shiftid": val.shiftid,
|
||||
"userid": val.userid,
|
||||
"orderid": orderid,
|
||||
"success": 0,
|
||||
"orderstatus": 'assigned',
|
||||
"processing": dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
"notifytype": 1,
|
||||
"notifyreason": 'Staff Assigned'
|
||||
// "sound": "ring",
|
||||
// "click_action": "FLUTTER_NOTIFICATION_CLICK",
|
||||
// "firstname": val.firstname
|
||||
|
||||
});
|
||||
tokenarr.push(val.userfcmtoken);
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
data2 = {
|
||||
"Title": "Staff Asigned",
|
||||
"message": `A Staff has been assigned to the order ${orderid}`,
|
||||
"tenantid": tenantid,
|
||||
"orderheaderid": orderheaderid,
|
||||
"orderid": orderid,
|
||||
"configid": 2,
|
||||
// "click_action": "FLUTTER_NOTIFICATION_CLICK"
|
||||
}
|
||||
let fcmmodel = {
|
||||
"priority": "high",
|
||||
"registration_ids": tokenarr,
|
||||
"data": data2,
|
||||
"notification": {
|
||||
"body": `An order has been assigned ${orderid}`,
|
||||
"title": "Legendary",
|
||||
"sound": "ring",
|
||||
"content_available": true,
|
||||
"click_action": "FLUTTER_NOTIFICATION_CLICK"
|
||||
}
|
||||
}
|
||||
let grpnotifyobj = {
|
||||
"notifications": arr1,
|
||||
"fcmmodel": fcmmodel
|
||||
}
|
||||
logger.info("grpnotifyobj")
|
||||
logger.info(grpnotifyobj)
|
||||
sendgroupnotification(grpnotifyobj)
|
||||
// notificationpush(obj2, val.userfcmtoken);
|
||||
// notificationpush(arr1,tokenarr);
|
||||
// enqueueSnackbar('Notifications sent successfully', {
|
||||
// variant: 'success', anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
||||
// autoHideDuration: 2000
|
||||
// })
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(err)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
const sendgroupnotification = async (obj1) => {
|
||||
|
||||
logger.info(obj1)
|
||||
|
||||
@@ -256,7 +256,7 @@ const MultipleOrders = () => {
|
||||
const tenantid = localStorage.getItem('tenantid');
|
||||
|
||||
// ============================== state ==============================
|
||||
const [locations, setLocations] = useState([]);
|
||||
const [, setLocations] = useState([]);
|
||||
const [tenantLocations, setTenantlocations] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [btnLoading, setBtnLoading] = useState(false);
|
||||
|
||||
@@ -30,7 +30,7 @@ import { useHotkeyFocus } from 'components/nearle_components/useHotkeyFocus';
|
||||
import DateFilterDialog from 'components/nearle_components/DateFilterDialog';
|
||||
import CircularLoader from 'components/nearle_components/CircularLoader';
|
||||
import { useQuery, useMutation, useInfiniteQuery } from '@tanstack/react-query';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import logger from 'utils/logger';
|
||||
import {
|
||||
fetchPercentageData,
|
||||
@@ -141,7 +141,6 @@ const scrollbarStyle = `
|
||||
|
||||
const Orders = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const tid = localStorage.getItem('tenantid');
|
||||
const loadMoreRef = useRef();
|
||||
const containerRef = useRef();
|
||||
@@ -162,7 +161,6 @@ const Orders = () => {
|
||||
const [debouncedSearch, setDebouncedSearch] = useState('');
|
||||
|
||||
// Floating button and Dialog states
|
||||
const [speedDialOpen, setSpeedDialOpen] = useState(false);
|
||||
const [multiDeleteDialog, setMultiDeleteDialog] = useState(false);
|
||||
const [createloader, setCreateloader] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@@ -190,7 +188,6 @@ const Orders = () => {
|
||||
|
||||
// React Queries
|
||||
const {
|
||||
data: percentageData,
|
||||
isLoading: fetchpercentageIsLoading,
|
||||
refetch: percentagedataRefetch
|
||||
} = useQuery({
|
||||
@@ -378,12 +375,6 @@ const Orders = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// KPI tile definitions.
|
||||
const kpiCards = [
|
||||
{ key: 'created', label: 'Created Orders', color: BRAND, icon: MdLocalShipping, value: percentageData?.created, percentage: percentageData?.percentage1 },
|
||||
{ key: 'pending', label: 'Pending Orders', color: '#f59e0b', icon: MdHourglassEmpty, value: percentageData?.uncoveredOrders, percentage: percentageData?.percentage2 }
|
||||
];
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<style>{scrollbarStyle}</style>
|
||||
@@ -648,17 +639,6 @@ const Orders = () => {
|
||||
)}
|
||||
|
||||
{rows.map((row, index) => {
|
||||
const isItemSelected = !!deliverylist.find((res) => res.orderheaderid === row.orderheaderid);
|
||||
const handleCheckbox = (e) => {
|
||||
if (e.target.checked) {
|
||||
setDeliverylist((prev) => [...prev, { ...row, sno: prev.length + 1 }]);
|
||||
} else {
|
||||
setDeliverylist((prev) =>
|
||||
prev.filter((item) => item.orderheaderid !== row.orderheaderid).map((item, i) => ({ ...item, sno: i + 1 }))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<tr key={`${row.orderheaderid}-${index}`} className="ordpg-row" style={{ cursor: 'pointer', transition: 'background-color 0.12s, box-shadow 0.12s' }}>
|
||||
<td style={{ borderBottom: `1px solid ${DT.divider}`, padding: '5px 8px', verticalAlign: 'top' }}>
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import { LoadScriptNext, GoogleMap, Marker, OverlayView } from '@react-google-maps/api';
|
||||
import { MapContainer, TileLayer, Marker, Tooltip } from 'react-leaflet';
|
||||
import L from 'leaflet';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
|
||||
import logger from 'utils/logger';
|
||||
import { DT, tint } from 'themes/dt/tokens';
|
||||
@@ -11,106 +13,81 @@ const containerStyle = {
|
||||
const C_ACTIVE = '#10b981';
|
||||
const C_INACTIVE = '#ef4444';
|
||||
|
||||
const GreenIcon = new L.Icon({
|
||||
iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
|
||||
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
|
||||
iconSize: [25, 41],
|
||||
iconAnchor: [12, 41],
|
||||
shadowSize: [41, 41]
|
||||
});
|
||||
|
||||
const RedIcon = new L.Icon({
|
||||
iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png',
|
||||
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
|
||||
iconSize: [25, 41],
|
||||
iconAnchor: [12, 41],
|
||||
shadowSize: [41, 41]
|
||||
});
|
||||
|
||||
export default function RiderLocationMap({ riderLocations }) {
|
||||
logger.info('riderLocations', riderLocations);
|
||||
|
||||
const center = {
|
||||
lat: Number(riderLocations?.[0]?.latitude || 11.0056),
|
||||
lng: Number(riderLocations?.[0]?.longitude || 76.9661)
|
||||
};
|
||||
const GreenIcon = {
|
||||
url: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
|
||||
scaledSize: new window.google.maps.Size(25, 41),
|
||||
anchor: new window.google.maps.Point(12, 41)
|
||||
};
|
||||
|
||||
const RedIcon = {
|
||||
url: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png',
|
||||
scaledSize: new window.google.maps.Size(25, 41),
|
||||
anchor: new window.google.maps.Point(12, 41)
|
||||
};
|
||||
const center = [Number(riderLocations?.[0]?.latitude || 11.0056), Number(riderLocations?.[0]?.longitude || 76.9661)];
|
||||
|
||||
return (
|
||||
<LoadScriptNext googleMapsApiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY}>
|
||||
<GoogleMap mapContainerStyle={containerStyle} zoom={12} center={center}>
|
||||
{riderLocations &&
|
||||
riderLocations?.map((r, index) => {
|
||||
const lat = Number(r.latitude);
|
||||
const lng = Number(r.longitude);
|
||||
const isActive = r.status == 'active';
|
||||
const statusColor = isActive ? C_ACTIVE : C_INACTIVE;
|
||||
return (
|
||||
<div key={index}>
|
||||
{/* Marker */}
|
||||
<Marker position={{ lat, lng }} icon={isActive ? GreenIcon : RedIcon} />
|
||||
{/* Rider details card — floats just above the pin, doesn't cover it */}
|
||||
<OverlayView position={{ lat, lng }} mapPaneName={OverlayView.OVERLAY_LAYER}>
|
||||
<div
|
||||
<MapContainer center={center} zoom={12} style={containerStyle}>
|
||||
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution="© OpenStreetMap contributors" />
|
||||
{riderLocations &&
|
||||
riderLocations.map((r, index) => {
|
||||
const lat = Number(r.latitude);
|
||||
const lng = Number(r.longitude);
|
||||
const isActive = r.status == 'active';
|
||||
const statusColor = isActive ? C_ACTIVE : C_INACTIVE;
|
||||
return (
|
||||
<Marker key={index} position={[lat, lng]} icon={isActive ? GreenIcon : RedIcon}>
|
||||
{/* Rider details card — permanent tooltip floats just above the pin */}
|
||||
<Tooltip permanent direction="top" offset={[0, -38]} opacity={1} className="rider-location-tooltip">
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
padding: '6px 10px',
|
||||
borderRadius: DT.radiusInner,
|
||||
backgroundColor: DT.surface,
|
||||
whiteSpace: 'nowrap'
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
transform: 'translate(-50%, -100%)',
|
||||
marginTop: -46,
|
||||
pointerEvents: 'none',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center'
|
||||
width: 7,
|
||||
height: 7,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: statusColor,
|
||||
boxShadow: `0 0 0 3px ${tint(statusColor)}`,
|
||||
flexShrink: 0
|
||||
}}
|
||||
>
|
||||
<div
|
||||
/>
|
||||
<span style={{ fontSize: 12, fontWeight: 700, color: DT.textPrimary }}>{r.username}</span>
|
||||
{r.orderid && (
|
||||
<span
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
padding: '6px 10px',
|
||||
borderRadius: DT.radiusInner,
|
||||
backgroundColor: DT.surface,
|
||||
border: `1px solid ${DT.borderSubtle}`,
|
||||
boxShadow: DT.shadowPop,
|
||||
whiteSpace: 'nowrap'
|
||||
fontSize: 10.5,
|
||||
fontWeight: 700,
|
||||
color: DT.brand,
|
||||
backgroundColor: tint(DT.brand),
|
||||
padding: '1px 6px',
|
||||
borderRadius: DT.radiusPill
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
width: 7,
|
||||
height: 7,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: statusColor,
|
||||
boxShadow: `0 0 0 3px ${tint(statusColor)}`,
|
||||
flexShrink: 0
|
||||
}}
|
||||
/>
|
||||
<span style={{ fontSize: 12, fontWeight: 700, color: DT.textPrimary }}>{r.username}</span>
|
||||
{r.orderid && (
|
||||
<span
|
||||
style={{
|
||||
fontSize: 10.5,
|
||||
fontWeight: 700,
|
||||
color: DT.brand,
|
||||
backgroundColor: tint(DT.brand),
|
||||
padding: '1px 6px',
|
||||
borderRadius: DT.radiusPill
|
||||
}}
|
||||
>
|
||||
#{r.orderid}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{/* Pointer connecting the card to the marker below it */}
|
||||
<div
|
||||
style={{
|
||||
width: 0,
|
||||
height: 0,
|
||||
borderLeft: '5px solid transparent',
|
||||
borderRight: '5px solid transparent',
|
||||
borderTop: `6px solid ${DT.surface}`,
|
||||
filter: 'drop-shadow(0 1px 1px rgba(15, 23, 42, 0.08))'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</OverlayView>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</GoogleMap>
|
||||
</LoadScriptNext>
|
||||
#{r.orderid}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Marker>
|
||||
);
|
||||
})}
|
||||
</MapContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ export default function OrdersReport() {
|
||||
const [enddate, setEnddate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const [openRow, setOpenRow] = useState(null);
|
||||
const [datestatus, setDatestatus] = useState('Today');
|
||||
const [total, settotal] = useState(0);
|
||||
const [, settotal] = useState(0);
|
||||
const [totalOrders, settotalOrders] = useState(0);
|
||||
const [totalOrderPend, setTotalOrderPend] = useState(0);
|
||||
const [totalOrderComplete, setTotalOrderComplete] = useState(0);
|
||||
|
||||
@@ -256,8 +256,8 @@ export default function OrdersDetails() {
|
||||
const [startdate, setStartdate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const [enddate, setEnddate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const [datestatus, setDatestatus] = useState('Today');
|
||||
const [totalCharge, settotalCharge] = useState(0);
|
||||
const [totalAmount, settotalAmount] = useState(0);
|
||||
const [, settotalCharge] = useState(0);
|
||||
const [, settotalAmount] = useState(0);
|
||||
const [searchword, setSearchword] = useState('');
|
||||
|
||||
// Density toggle — operators choose how many rows to surface per screen.
|
||||
|
||||
@@ -4,8 +4,6 @@ import { lazy } from 'react';
|
||||
import MainLayout from 'layout/MainLayout';
|
||||
import CommonLayout from 'layout/CommonLayout';
|
||||
import Loadable from 'components/Loadable';
|
||||
import AuthGuard from 'utils/route-guard/AuthGuard';
|
||||
import { element } from 'prop-types';
|
||||
|
||||
// pages routing
|
||||
const MaintenanceError = Loadable(lazy(() => import('pages/maintenance/404')));
|
||||
@@ -13,8 +11,6 @@ const MaintenanceError500 = Loadable(lazy(() => import('pages/maintenance/500'))
|
||||
const MaintenanceUnderConstruction = Loadable(lazy(() => import('pages/maintenance/under-construction')));
|
||||
const MaintenanceComingSoon = Loadable(lazy(() => import('pages/maintenance/coming-soon')));
|
||||
|
||||
// render - sample page
|
||||
const SamplePage = Loadable(lazy(() => import('pages/extra-pages/sample-page')));
|
||||
const Login = Loadable(lazy(() => import('pages/nearle/login')));
|
||||
|
||||
const Customers = Loadable(lazy(() => import('pages/nearle/clients/customers')));
|
||||
|
||||
90
src/utils/addressSearch.js
Normal file
90
src/utils/addressSearch.js
Normal file
@@ -0,0 +1,90 @@
|
||||
// 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; Astryx's `Typeahead`
|
||||
// debounces queries internally (see `debounceMs` at each call site) and
|
||||
// `createAddressSearchSource` aborts any still-in-flight request whenever a
|
||||
// newer query supersedes it.
|
||||
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
|
||||
// (name, formatted_address, geometry.location.lat()/lng(), address_components)
|
||||
// that call sites only needed mechanical edits, not rewrites, when swapping
|
||||
// off Google.
|
||||
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;
|
||||
};
|
||||
|
||||
// Builds a `SearchSource` for Astryx's `<Typeahead searchSource={...} />` —
|
||||
// each result is `{ id, label, auxiliaryData }` where `auxiliaryData` is the
|
||||
// `toPlace`-shaped object call sites parse via `address_components`.
|
||||
export function createAddressSearchSource({ bias } = {}) {
|
||||
let controller = null;
|
||||
return {
|
||||
async search(query) {
|
||||
if (!query) return [];
|
||||
controller?.abort();
|
||||
controller = new AbortController();
|
||||
try {
|
||||
const params = buildParams(query, bias);
|
||||
const res = await fetch(`${NOMINATIM_SEARCH_URL}?${params.toString()}`, {
|
||||
headers: { Accept: 'application/json' },
|
||||
signal: controller.signal
|
||||
});
|
||||
if (!res.ok) return [];
|
||||
const results = await res.json();
|
||||
return (results || []).map((result) => ({
|
||||
id: String(result.place_id),
|
||||
label: result.display_name,
|
||||
auxiliaryData: toPlace(result)
|
||||
}));
|
||||
} catch (err) {
|
||||
if (err.name === 'AbortError') return [];
|
||||
console.error('address search error:', err);
|
||||
return [];
|
||||
}
|
||||
},
|
||||
bootstrap() {
|
||||
return [];
|
||||
},
|
||||
cancel() {
|
||||
controller?.abort();
|
||||
}
|
||||
};
|
||||
}
|
||||
85
yarn.lock
85
yarn.lock
@@ -1408,19 +1408,6 @@
|
||||
intl-messageformat "10.7.18"
|
||||
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"
|
||||
|
||||
"@humanwhocodes/config-array@^0.11.8":
|
||||
version "0.11.8"
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz"
|
||||
@@ -1837,28 +1824,6 @@
|
||||
resolved "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz"
|
||||
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":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz"
|
||||
@@ -2314,11 +2279,6 @@
|
||||
"@types/qs" "*"
|
||||
"@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":
|
||||
version "4.1.5"
|
||||
resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz"
|
||||
@@ -3148,13 +3108,6 @@ autoprefixer@^10.4.11:
|
||||
picocolors "^1.0.0"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
autosuggest-highlight@^3.3.4:
|
||||
version "3.3.4"
|
||||
resolved "https://registry.npmjs.org/autosuggest-highlight/-/autosuggest-highlight-3.3.4.tgz"
|
||||
integrity sha512-j6RETBD2xYnrVcoV1S5R4t3WxOlWZKyDQjkwnggDPSjF5L4jV98ZltBpvPvbkM1HtoSe5o+bNrTHyjPbieGeYA==
|
||||
dependencies:
|
||||
remove-accents "^0.4.2"
|
||||
|
||||
available-typed-arrays@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz"
|
||||
@@ -6098,7 +6051,7 @@ intl-messageformat@10.7.18:
|
||||
"@formatjs/icu-messageformat-parser" "2.11.4"
|
||||
tslib "^2.8.0"
|
||||
|
||||
invariant@^2.2.4, invariant@2.2.4:
|
||||
invariant@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz"
|
||||
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
|
||||
@@ -7061,11 +7014,6 @@ jwt-decode@^3.1.2:
|
||||
resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz"
|
||||
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==
|
||||
|
||||
kind-of@^6.0.2:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
|
||||
@@ -8517,7 +8465,7 @@ prompts@^2.0.1, prompts@^2.4.2:
|
||||
kleur "^3.0.3"
|
||||
sisteransi "^1.0.5"
|
||||
|
||||
prop-types@^15.5.0, prop-types@^15.8.1:
|
||||
prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@@ -9080,21 +9028,6 @@ react-fast-compare@^2.0.1:
|
||||
resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz"
|
||||
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.3"
|
||||
resolved "https://registry.npmjs.org/react-google-autocomplete/-/react-google-autocomplete-2.7.3.tgz"
|
||||
integrity sha512-Nm+7/VDe7/NDWb8p/a39is7ktNqt5bNqAOoQv2Ev/XkuEvjsRk08VAPFmXUH03xKuM8IUuDrk2Lwfge44YEj6Q==
|
||||
dependencies:
|
||||
lodash.debounce "^4.0.8"
|
||||
prop-types "^15.5.0"
|
||||
|
||||
react-icons@^4.12.0:
|
||||
version "4.12.0"
|
||||
resolved "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz"
|
||||
@@ -9355,7 +9288,7 @@ regenerate@^1.4.2:
|
||||
resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz"
|
||||
integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
|
||||
|
||||
regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.9:
|
||||
regenerator-runtime@^0.13.9:
|
||||
version "0.13.11"
|
||||
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz"
|
||||
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
|
||||
@@ -9408,11 +9341,6 @@ relateurl@^0.2.7:
|
||||
resolved "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz"
|
||||
integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==
|
||||
|
||||
remove-accents@^0.4.2:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.4.tgz"
|
||||
integrity sha512-EpFcOa/ISetVHEXqu+VwI96KZBmq+a8LJnGkaeFw45epGlxIZz5dhEEnNZMsQXgORu3qaMoLX4qJCzOik6ytAg==
|
||||
|
||||
renderkid@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz"
|
||||
@@ -10150,13 +10078,6 @@ stylis@^4.0.13:
|
||||
resolved "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz"
|
||||
integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==
|
||||
|
||||
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:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
|
||||
|
||||
Reference in New Issue
Block a user