overall updates

This commit is contained in:
joshikannan
2025-11-26 18:24:03 +05:30
parent 12df2e9dc4
commit e71e44319c
35 changed files with 3145 additions and 2404 deletions

156
package-lock.json generated
View File

@@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@ant-design/colors": "^7.0.0", "@ant-design/colors": "^7.0.0",
"@ant-design/icons": "^5.0.1", "@ant-design/icons": "^5.0.1",
"@custom-react-hooks/use-network": "^1.0.1",
"@emotion/cache": "^11.10.7", "@emotion/cache": "^11.10.7",
"@emotion/react": "^11.10.6", "@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6", "@emotion/styled": "^11.10.6",
@@ -18,6 +19,7 @@
"@mui/lab": "^5.0.0-alpha.127", "@mui/lab": "^5.0.0-alpha.127",
"@mui/material": "^5.12.1", "@mui/material": "^5.12.1",
"@mui/x-date-pickers": "^6.18.2", "@mui/x-date-pickers": "^6.18.2",
"@react-google-maps/api": "^2.20.7",
"@reduxjs/toolkit": "^1.9.5", "@reduxjs/toolkit": "^1.9.5",
"@svgr/webpack": "^7.0.0", "@svgr/webpack": "^7.0.0",
"@tanstack/react-query": "^5.22.2", "@tanstack/react-query": "^5.22.2",
@@ -2267,6 +2269,15 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/@custom-react-hooks/use-network": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@custom-react-hooks/use-network/-/use-network-1.0.1.tgz",
"integrity": "sha512-WbFVxsC18hjJiVIONAExVORlJlrOeYwzKsiYUCzrt5zCP0u9eLUPJuftF3DvEpoaQdjufazllWCPWKXT+dTY2g==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@emotion/babel-plugin": { "node_modules/@emotion/babel-plugin": {
"version": "11.10.6", "version": "11.10.6",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz",
@@ -2624,6 +2635,22 @@
"tslib": "^2.4.0" "tslib": "^2.4.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": { "node_modules/@humanwhocodes/config-array": {
"version": "0.11.8", "version": "0.11.8",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
@@ -4111,6 +4138,36 @@
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
"integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA=="
}, },
"node_modules/@react-google-maps/api": {
"version": "2.20.7",
"resolved": "https://registry.npmjs.org/@react-google-maps/api/-/api-2.20.7.tgz",
"integrity": "sha512-ys7uri3V6gjhYZUI43srHzSKDC6/jiKTwHNlwXFTvjeaJE3M3OaYBt9FZKvJs8qnOhL6i6nD1BKJoi1KrnkCkg==",
"license": "MIT",
"dependencies": {
"@googlemaps/js-api-loader": "1.16.8",
"@googlemaps/markerclusterer": "2.5.3",
"@react-google-maps/infobox": "2.20.0",
"@react-google-maps/marker-clusterer": "2.20.0",
"@types/google.maps": "3.58.1",
"invariant": "2.2.4"
},
"peerDependencies": {
"react": "^16.8 || ^17 || ^18 || ^19",
"react-dom": "^16.8 || ^17 || ^18 || ^19"
}
},
"node_modules/@react-google-maps/infobox": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/@react-google-maps/infobox/-/infobox-2.20.0.tgz",
"integrity": "sha512-03PJHjohhaVLkX6+NHhlr8CIlvUxWaXhryqDjyaZ8iIqqix/nV8GFdz9O3m5OsjtxtNho09F/15j14yV0nuyLQ==",
"license": "MIT"
},
"node_modules/@react-google-maps/marker-clusterer": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/@react-google-maps/marker-clusterer/-/marker-clusterer-2.20.0.tgz",
"integrity": "sha512-tieX9Va5w1yP88vMgfH1pHTacDQ9TgDTjox3tLlisKDXRQWdjw+QeVVghhf5XqqIxXHgPdcGwBvKY6UP+SIvLw==",
"license": "MIT"
},
"node_modules/@react-leaflet/core": { "node_modules/@react-leaflet/core": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz",
@@ -4905,6 +4962,12 @@
"@types/range-parser": "*" "@types/range-parser": "*"
} }
}, },
"node_modules/@types/google.maps": {
"version": "3.58.1",
"resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.58.1.tgz",
"integrity": "sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==",
"license": "MIT"
},
"node_modules/@types/graceful-fs": { "node_modules/@types/graceful-fs": {
"version": "4.1.5", "version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
@@ -10699,6 +10762,15 @@
"tslib": "^2.4.0" "tslib": "^2.4.0"
} }
}, },
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/ipaddr.js": { "node_modules/ipaddr.js": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
@@ -13433,6 +13505,12 @@
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz",
"integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="
}, },
"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": { "node_modules/kind-of": {
"version": "6.0.3", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@@ -18872,6 +18950,15 @@
"stylis": "4.x" "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": { "node_modules/supports-color": {
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -22001,6 +22088,12 @@
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
"integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==" "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA=="
}, },
"@custom-react-hooks/use-network": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@custom-react-hooks/use-network/-/use-network-1.0.1.tgz",
"integrity": "sha512-WbFVxsC18hjJiVIONAExVORlJlrOeYwzKsiYUCzrt5zCP0u9eLUPJuftF3DvEpoaQdjufazllWCPWKXT+dTY2g==",
"requires": {}
},
"@emotion/babel-plugin": { "@emotion/babel-plugin": {
"version": "11.10.6", "version": "11.10.6",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz",
@@ -22292,6 +22385,20 @@
"tslib": "^2.4.0" "tslib": "^2.4.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": { "@humanwhocodes/config-array": {
"version": "0.11.8", "version": "0.11.8",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
@@ -23231,6 +23338,29 @@
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
"integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA=="
}, },
"@react-google-maps/api": {
"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": { "@react-leaflet/core": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz",
@@ -23772,6 +23902,11 @@
"@types/range-parser": "*" "@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": { "@types/graceful-fs": {
"version": "4.1.5", "version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
@@ -28074,6 +28209,14 @@
"tslib": "^2.4.0" "tslib": "^2.4.0"
} }
}, },
"invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"requires": {
"loose-envify": "^1.0.0"
}
},
"ipaddr.js": { "ipaddr.js": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
@@ -30040,6 +30183,11 @@
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz",
"integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="
}, },
"kdbush": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz",
"integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA=="
},
"kind-of": { "kind-of": {
"version": "6.0.3", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@@ -33782,6 +33930,14 @@
"cssjanus": "^2.0.1" "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": { "supports-color": {
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",

View File

@@ -5,6 +5,7 @@
"dependencies": { "dependencies": {
"@ant-design/colors": "^7.0.0", "@ant-design/colors": "^7.0.0",
"@ant-design/icons": "^5.0.1", "@ant-design/icons": "^5.0.1",
"@custom-react-hooks/use-network": "^1.0.1",
"@emotion/cache": "^11.10.7", "@emotion/cache": "^11.10.7",
"@emotion/react": "^11.10.6", "@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6", "@emotion/styled": "^11.10.6",
@@ -13,6 +14,7 @@
"@mui/lab": "^5.0.0-alpha.127", "@mui/lab": "^5.0.0-alpha.127",
"@mui/material": "^5.12.1", "@mui/material": "^5.12.1",
"@mui/x-date-pickers": "^6.18.2", "@mui/x-date-pickers": "^6.18.2",
"@react-google-maps/api": "^2.20.7",
"@reduxjs/toolkit": "^1.9.5", "@reduxjs/toolkit": "^1.9.5",
"@svgr/webpack": "^7.0.0", "@svgr/webpack": "^7.0.0",
"@tanstack/react-query": "^5.22.2", "@tanstack/react-query": "^5.22.2",

View File

@@ -8,6 +8,7 @@ import Snackbar from 'components/@extended/Snackbar';
import Notistack from 'components/third-party/Notistack'; import Notistack from 'components/third-party/Notistack';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import { useEffect } from 'react'; import { useEffect } from 'react';
import InternetStatus from 'components/nearle_components/updateNetworkStatus';
// auth-provider // auth-provider
// import { JWTProvider as AuthProvider } from 'contexts/JWTContext'; // import { JWTProvider as AuthProvider } from 'contexts/JWTContext';
@@ -15,16 +16,15 @@ import { useEffect } from 'react';
const App = () => { const App = () => {
let navigate = useNavigate(); let navigate = useNavigate();
useEffect(() => { useEffect(() => {
if (!localStorage.getItem('authname')) { if (!localStorage.getItem('authname')) {
navigate('/login'); navigate('/login');
} }
}, []); }, []);
return ( return (
<> <>
<ThemeCustomization> <ThemeCustomization>
<InternetStatus />
{/* <RTLLayout> */} {/* <RTLLayout> */}
<Locales> <Locales>
<ScrollTop> <ScrollTop>

View File

@@ -5,7 +5,9 @@ import { Box, Card, CardContent, Grid, Typography } from '@mui/material';
// ===========================|| HOVER SOCIAL CARD ||=========================== // // ===========================|| HOVER SOCIAL CARD ||=========================== //
const HoverSocialCard = ({ primary, secondary, const HoverSocialCard = ({
primary,
secondary,
percentage, percentage,
// iconPrimary, // iconPrimary,
color color
@@ -20,10 +22,10 @@ const HoverSocialCard = ({ primary, secondary,
background: color, background: color,
position: 'relative', position: 'relative',
color: '#fff', color: '#fff',
// '&:hover svg': { '&:hover svg': {
// opacity: 1, opacity: 1,
// transform: 'scale(1.1)' transform: 'scale(1.1)'
// } }
}} }}
> >
<CardContent> <CardContent>
@@ -33,18 +35,17 @@ const HoverSocialCard = ({ primary, secondary,
right: 15, right: 15,
top: 25, top: 25,
color: '#fff', color: '#fff',
// '& svg': { '& svg': {
// width: 36, width: 36,
// height: 36, height: 36,
// opacity: 0.5, opacity: 0.5,
// transition: 'all .3s ease-in-out' transition: 'all .3s ease-in-out'
// } }
}} }}
> >
<Typography variant="h2" color="inherit"> <Typography variant="h2" color="inherit">
{/* {percentage.toString()} % */} {/* {percentage.toString()} % */}
{(percentage)? `${percentage.toString()} %`:''} {percentage ? `${percentage.toString()} %` : ''}
</Typography> </Typography>
{/* {primaryIcon} */} {/* {primaryIcon} */}
</Box> </Box>

View File

@@ -0,0 +1,55 @@
import { Dialog, DialogTitle, DialogContent, Typography, Stack, Button, DialogActions, Paper } from '@mui/material';
import { DateRangePicker } from 'mui-daterange-picker';
import dayjs from 'dayjs';
import { addDays, addWeeks, addMonths, startOfWeek, endOfWeek, startOfMonth, endOfMonth } from 'date-fns';
export default function DateFilterDialog({ open, onClose, onApply }) {
const definedRanges = [
{ label: 'Today', startDate: new Date(), endDate: new Date() },
{ label: 'Yesterday', startDate: addDays(new Date(), -1), endDate: addDays(new Date(), -1) },
{ label: 'Tomorrow', startDate: addDays(new Date(), 1), endDate: addDays(new Date(), 1) },
{ label: 'This Week', startDate: startOfWeek(new Date()), endDate: endOfWeek(new Date()) },
{ label: 'Last Week', startDate: startOfWeek(addWeeks(new Date(), -1)), endDate: endOfWeek(addWeeks(new Date(), -1)) },
{ label: 'Last 7 Days', startDate: addDays(new Date(), -7), endDate: new Date() },
{ label: 'This Month', startDate: startOfMonth(new Date()), endDate: endOfMonth(new Date()) },
{ label: 'Last Month', startDate: startOfMonth(addMonths(new Date(), -1)), endDate: endOfMonth(addMonths(new Date(), -1)) }
];
const handleSelect = (range) => {
if (!range?.startDate || !range?.endDate) return;
onApply({
startDate: dayjs(range.startDate).format('YYYY-MM-DD'),
endDate: dayjs(range.endDate).format('YYYY-MM-DD'),
label: range.label || ''
});
onClose();
};
return (
<Dialog open={open} onClose={onClose} fullWidth maxWidth="sm">
<DialogTitle disableTypography>
<Stack display="flex" flexDirection="row" justifyContent="space-between" alignItems="center" sx={{ width: '100%' }}>
<Typography variant="h4">Select Date Range</Typography>
</Stack>
</DialogTitle>
<DialogContent
sx={{
'& .MuiPaper-root': {
boxShadow: 'none !important'
}
}}
>
<DateRangePicker open={open} toggle={onClose} definedRanges={definedRanges} onChange={handleSelect} closeOnClickOutside={false} />
</DialogContent>
<DialogActions>
<Button variant="contained" onClick={onClose} sx={{ cursor: 'pointer' }}>
Close
</Button>
</DialogActions>
</Dialog>
);
}

View File

@@ -0,0 +1,58 @@
// SearchBar.jsx
import React, { useEffect, useRef } from 'react';
import { FormControl, OutlinedInput, InputAdornment, IconButton, useTheme } from '@mui/material';
import SearchOutlined from '@mui/icons-material/SearchOutlined';
import ClearIcon from '@mui/icons-material/Clear';
const SearchBar = ({ value, onChange, sx, placeholder = 'Search (Ctrl + K)' }) => {
const theme = useTheme();
const inputRef = useRef(null);
/* ============================================= || handleKeyPress (CTRL + K) and ESC ||============================================= */
useEffect(() => {
const handleKeyPress = (event) => {
// Focus input with CTRL + K / CMD + K
if (event.key === 'k' && (event.metaKey || event.ctrlKey)) {
event.preventDefault();
inputRef.current?.focus();
}
// ESC removes focus
if (event.key === 'Escape' && document.activeElement === inputRef.current) {
inputRef.current.blur();
}
};
document.addEventListener('keydown', handleKeyPress);
return () => document.removeEventListener('keydown', handleKeyPress);
}, []);
return (
<FormControl fullWidth sx={{}}>
<OutlinedInput
inputRef={inputRef}
placeholder={placeholder}
sx={{
borderRadius: 0,
...sx
}}
value={value}
onChange={onChange}
autoComplete="off"
size="large"
startAdornment={
<InputAdornment position="start" sx={{ mr: -0.5, color: theme.palette.primary.main }}>
<SearchOutlined />
</InputAdornment>
}
endAdornment={
<IconButton sx={{ visibility: value ? 'visible' : 'hidden' }} onClick={() => onChange({ target: { value: '' } })}>
<ClearIcon style={{ fontSize: 'large', color: theme.palette.primary.main }} />
</IconButton>
}
/>
</FormControl>
);
};
export default SearchBar;

View File

@@ -0,0 +1,96 @@
import { useEffect, useState, useRef } from 'react';
import { useTheme } from '@mui/material/styles';
import WifiOffIcon from '@mui/icons-material/WifiOff';
import WifiIcon from '@mui/icons-material/Wifi';
const NOTIFICATION_STYLE = {
position: 'fixed',
top: '10px', // Keep top spacing
left: '50%', // Center horizontally
transform: 'translateX(-50%)', // Offset to truly center
padding: '12px 40px',
borderRadius: '8px',
color: 'white',
fontWeight: '500',
fontSize: '14px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
zIndex: 9999,
maxWidth: '90%',
minWidth: 'auto',
textAlign: 'center'
};
const InternetStatus = () => {
const theme = useTheme();
const [isOnline, setIsOnline] = useState(navigator.onLine);
const [showBackOnline, setShowBackOnline] = useState(false);
const wasOffline = useRef(!navigator.onLine);
useEffect(() => {
const handleNetworkChange = () => {
const online = navigator.onLine;
setIsOnline(online);
if (online && wasOffline.current) {
console.log('✅ Back online');
setShowBackOnline(true);
wasOffline.current = false;
// window.location.reload();
setTimeout(() => {
setShowBackOnline(false);
}, 2000);
}
if (!online) {
console.log('❌ No internet connection');
wasOffline.current = true;
setShowBackOnline(false);
}
};
window.addEventListener('online', handleNetworkChange);
window.addEventListener('offline', handleNetworkChange);
return () => {
window.removeEventListener('online', handleNetworkChange);
window.removeEventListener('offline', handleNetworkChange);
};
}, []);
return (
<>
{!isOnline && (
<div
style={{
...NOTIFICATION_STYLE,
backgroundColor: theme.palette.error.main,
display: 'flex',
alignItems: 'center',
gap: '10px'
}}
>
<WifiOffIcon style={{ color: '#fff' }} />
No Internet Connection
</div>
)}
{showBackOnline && (
<div
style={{
...NOTIFICATION_STYLE,
backgroundColor: theme.palette.success.main,
display: 'flex',
alignItems: 'center',
gap: '10px'
}}
>
<WifiIcon style={{ color: '#fff' }} />
Back Online
</div>
)}
</>
);
};
export default InternetStatus;

View File

@@ -0,0 +1,15 @@
import { useEffect, useState } from 'react';
export const useDebounce = (value, delay = 500) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(handler); // cleanup on every value change
}, [value, delay]);
return debouncedValue;
};

View File

@@ -0,0 +1,26 @@
import { useEffect } from 'react';
export const useHotkeyFocus = (ref, hotkey = 'k') => {
useEffect(() => {
if (!ref?.current) return;
const handleKeyPress = (event) => {
const isHotkey = event.key.toLowerCase() === hotkey.toLowerCase();
// CTRL + Hotkey
if (isHotkey && (event.metaKey || event.ctrlKey)) {
event.preventDefault();
ref.current?.focus();
}
// ESC to blur
if (event.key === 'Escape' && document.activeElement === ref.current) {
ref.current.blur();
}
};
document.addEventListener('keydown', handleKeyPress);
return () => document.removeEventListener('keydown', handleKeyPress);
}, [ref, hotkey]);
};

View File

@@ -11,7 +11,7 @@ import 'simplebar/dist/simplebar.css';
import 'assets/third-party/apex-chart.css'; import 'assets/third-party/apex-chart.css';
import 'assets/third-party/react-table.css'; import 'assets/third-party/react-table.css';
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// project import // project import
import App from './App'; import App from './App';

View File

@@ -211,7 +211,16 @@ const NavCollapse = ({ menu, level, parentId, setSelectedItems, selectedItems, s
const isSelected = selected === menu.id; const isSelected = selected === menu.id;
const borderIcon = level === 1 ? <BorderOutlined style={{ fontSize: '1rem' }} /> : false; const borderIcon = level === 1 ? <BorderOutlined style={{ fontSize: '1rem' }} /> : false;
const Icon = menu.icon; const Icon = menu.icon;
const menuIcon = menu.icon ? <Icon style={{ fontSize: drawerOpen ? '1rem' : '1.25rem', color: 'white' }} /> : borderIcon; const menuIcon = menu.icon ? (
<Icon
style={{
fontSize: drawerOpen ? '1rem' : '1.25rem'
// color: 'white'
}}
/>
) : (
borderIcon
);
// const textColor = theme.palette.mode === ThemeMode.DARK ? 'grey.400' : 'text.primary'; // const textColor = theme.palette.mode === ThemeMode.DARK ? 'grey.400' : 'text.primary';
// const iconSelectedColor = theme.palette.mode === ThemeMode.DARK && drawerOpen ? theme.palette.text.primary : theme.palette.primary.main; // const iconSelectedColor = theme.palette.mode === ThemeMode.DARK && drawerOpen ? theme.palette.text.primary : theme.palette.primary.main;
const popperId = miniMenuOpened ? `collapse-pop-${menu.id}` : undefined; const popperId = miniMenuOpened ? `collapse-pop-${menu.id}` : undefined;
@@ -237,11 +246,10 @@ const NavCollapse = ({ menu, level, parentId, setSelectedItems, selectedItems, s
sx={{ sx={{
pl: drawerOpen ? `${level * 28}px` : 1.5, pl: drawerOpen ? `${level * 28}px` : 1.5,
py: !drawerOpen && level === 1 ? 1.25 : 1, py: !drawerOpen && level === 1 ? 1.25 : 1,
...(drawerOpen && { ...(drawerOpen && {
'&:hover': { '&:hover': {
// bgcolor: theme.palette.mode === ThemeMode.DARK ? 'divider' : 'primary.lighter' // bgcolor: theme.palette.mode === ThemeMode.DARK ? 'divider' : 'primary.lighter',
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'divider' : '#7b1fa2' bgcolor: '#7b1fa2'
}, },
'&.Mui-selected': { '&.Mui-selected': {
bgcolor: 'transparent', bgcolor: 'transparent',
@@ -250,14 +258,14 @@ const NavCollapse = ({ menu, level, parentId, setSelectedItems, selectedItems, s
} }
}), }),
...(!drawerOpen && { ...(!drawerOpen && {
bgcolor: theme.palette.primary.main,
'&:hover': { '&:hover': {
bgcolor: 'transparent' bgcolor: theme.palette.primary.light
}, },
'&.Mui-selected': { '&.Mui-selected': {
'&:hover': { '&:hover': {
bgcolor: 'transparent' bgcolor: theme.palette.primary.light
}, }
bgcolor: 'transparent'
} }
}) })
}} }}
@@ -269,30 +277,25 @@ const NavCollapse = ({ menu, level, parentId, setSelectedItems, selectedItems, s
minWidth: 28, minWidth: 28,
// color: selected === menu.id ? 'primary.main' : textColor, // color: selected === menu.id ? 'primary.main' : textColor,
// color: selected === menu.id ? textColor : textColor, // color: selected === menu.id ? textColor : textColor,
// bgcolor:'white', // bgcolor:'white',
// color:'white', color: 'white',
...(!drawerOpen && { ...(!drawerOpen && {
borderRadius: 1.5, borderRadius: 1.5,
width: 36, width: 36,
height: 36, height: 36,
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
color: 'white',
'&:hover': { '&:hover': {
// bgcolor: theme.palette.mode === ThemeMode.DARK ? 'secondary.light' : 'secondary.lighter' bgcolor: theme.palette.primary.light
bgcolor: '#7b1fa2',
color: 'white'
} }
}), }),
...(!drawerOpen && ...(!drawerOpen &&
selected === menu.id && { selected === menu.id && {
// bgcolor: theme.palette.mode === ThemeMode.DARK ? 'primary.900' : 'primary.lighter', bgcolor: theme.palette.primary.lighter,
// bgcolor:'white', color: theme.palette.primary.main,
bgcolor: '#7b1fa2',
'&:hover': { '&:hover': {
// bgcolor: theme.palette.mode === ThemeMode.DARK ? 'primary.darker' : 'primary.lighter' bgcolor: theme.palette.primary.lighter
bgcolor: '#7b1fa2'
// color:'white'
} }
}) })
}} }}

View File

@@ -78,7 +78,7 @@ const NavItem = ({ item, level }) => {
{...listItemProps} {...listItemProps}
disabled={item.disabled} disabled={item.disabled}
selected={isSelected} selected={isSelected}
onMouseEnter={(e, val) => { onMouseEnter={(e) => {
console.log(e); console.log(e);
}} }}
onMouseLeave={() => { onMouseLeave={() => {
@@ -104,18 +104,15 @@ const NavItem = ({ item, level }) => {
} }
}), }),
...(!drawerOpen && { ...(!drawerOpen && {
bgcolor: '#662582', bgcolor: theme.palette.primary.main,
'&:hover': { '&:hover': {
// bgcolor: 'transparent', bgcolor: theme.palette.primary.light
// bgcolor:'#7b1fa2'
bgcolor: '#662582'
}, },
'&.Mui-selected': { '&.Mui-selected': {
'&:hover': { '&:hover': {
bgcolor: 'transparent' bgcolor: 'white'
}, },
bgcolor: 'transparent' bgcolor: 'white'
// bgcolor:'#7b1fa2'
} }
}) })
}} }}
@@ -133,15 +130,13 @@ const NavItem = ({ item, level }) => {
color: isSelected ? iconSelectedColor : textColor, color: isSelected ? iconSelectedColor : textColor,
...(!drawerOpen && { ...(!drawerOpen && {
borderRadius: 1.5,
width: 36, width: 36,
height: 36, height: 36,
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
'&:hover': { '&:hover': {
// bgcolor: theme.palette.mode === ThemeMode.DARK ? 'secondary.light' : 'secondary.lighter' // bgcolor: theme.palette.mode === ThemeMode.DARK ? 'secondary.light' : 'secondary.lighter'
bgcolor: '#7b1fa2' // bgcolor: theme.palette.primary.light
} }
}), }),
...(!drawerOpen && ...(!drawerOpen &&
@@ -149,7 +144,8 @@ const NavItem = ({ item, level }) => {
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'primary.900' : 'primary.lighter', bgcolor: theme.palette.mode === ThemeMode.DARK ? 'primary.900' : 'primary.lighter',
'&:hover': { '&:hover': {
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'primary.darker' : 'primary.lighter' bgcolor: theme.palette.mode === ThemeMode.DARK ? 'primary.darker' : 'primary.lighter'
} },
borderRadius: 2
}) })
}} }}
> >
@@ -164,7 +160,7 @@ const NavItem = ({ item, level }) => {
// sx={{ color: isSelected ? iconSelectedColor : textColor }} // sx={{ color: isSelected ? iconSelectedColor : textColor }}
sx={{ sx={{
color: isSelected && !drawerOpen ? theme.palette.primary.main : !isSelected ? 'white' : theme.palette.primary.main, color: isSelected && !drawerOpen ? theme.palette.primary.main : !isSelected ? 'white' : theme.palette.primary.main,
bgcolor: isSelected && !drawerOpen ? theme.palette.primary.lighter : 'none', bgcolor: isSelected && theme.palette.primary.lighter,
padding: isSelected && !drawerOpen ? 0.8 : 'none', padding: isSelected && !drawerOpen ? 0.8 : 'none',
borderRadius: isSelected && !drawerOpen ? 2 : 'none', borderRadius: isSelected && !drawerOpen ? 2 : 'none',
ml: isSelected && !drawerOpen ? 0.5 : 'none' ml: isSelected && !drawerOpen ? 0.5 : 'none'

View File

@@ -22,32 +22,33 @@ const ProfileTab = ({ handleLogout }) => {
return ( return (
<List component="nav" sx={{ p: 0, '& .MuiListItemIcon-root': { minWidth: 32 } }}> <List component="nav" sx={{ p: 0, '& .MuiListItemIcon-root': { minWidth: 32 } }}>
<ListItemButton selected={selectedIndex === 0} onClick={(event) => handleListItemClick(event, 0)}> {/* <ListItemButton selected={selectedIndex === 0} onClick={(event) => handleListItemClick(event, 0)}>
<ListItemIcon> <ListItemIcon>
<EditOutlined /> <EditOutlined />
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Edit Profile" /> <ListItemText primary="Edit Profile" />
</ListItemButton> </ListItemButton> */}
<ListItemButton selected={selectedIndex === 1} onClick={(event) => handleListItemClick(event, 1)}> <ListItemButton selected={selectedIndex === 0} onClick={(event) => handleListItemClick(event, 1)}>
<ListItemIcon> <ListItemIcon>
<UserOutlined /> <UserOutlined />
</ListItemIcon> </ListItemIcon>
<ListItemText primary="View Profile" /> <ListItemText primary="View Profile" />
</ListItemButton> </ListItemButton>
<ListItemButton selected={selectedIndex === 2} onClick={(event) => handleListItemClick(event, 2)}> {/* <ListItemButton selected={selectedIndex === 1} onClick={(event) => handleListItemClick(event, 2)}>
<ListItemIcon> <ListItemIcon>
<CommentOutlined /> <CommentOutlined />
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Support Ticket" /> <ListItemText primary="Support Ticket" />
</ListItemButton> </ListItemButton> */}
{/* <ListItemButton selected={selectedIndex === 4} onClick={(event) => handleListItemClick(event, 4)}> {/* <ListItemButton selected={selectedIndex === 4} onClick={(event) => handleListItemClick(event, 4)}>
<ListItemIcon> <ListItemIcon>
<WalletOutlined /> <WalletOutlined />
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Billing" /> <ListItemText primary="Billing" />
</ListItemButton> */} </ListItemButton> */}
<ListItemButton selected={selectedIndex === 3} <ListItemButton
selected={selectedIndex === 1}
onClick={handleLogout} onClick={handleLogout}
// onClick={()=>{ // onClick={()=>{
// navigate('/login') // navigate('/login')

View File

@@ -71,7 +71,7 @@ const HeaderContent = () => {
<Stack width="100%" direction="row" justifyContent="space-between" spacing={2} alignItems="center"> <Stack width="100%" direction="row" justifyContent="space-between" spacing={2} alignItems="center">
{/* {!matchesXs && megaMenu} */} {/* {!matchesXs && megaMenu} */}
<Typography variant="h5" sx={{ ml: 2, color: '#fff', whiteSpace: 'nowrap' }}> <Typography variant="h5" sx={{ ml: 2, color: '#fff', whiteSpace: 'nowrap' }}>
{localStorage.getItem('fullname') || ''} {localStorage.getItem('tenantname') || ''}
</Typography> </Typography>
{matchesXs && <Box sx={{ width: '100%', ml: 1 }} />} {matchesXs && <Box sx={{ width: '100%', ml: 1 }} />}
<Stack direction={'row'} spacing={2}> <Stack direction={'row'} spacing={2}>
@@ -169,7 +169,7 @@ const HeaderContent = () => {
<ListItemIcon sx={{ mr: 1, fontSize: '20px' }}> <ListItemIcon sx={{ mr: 1, fontSize: '20px' }}>
<TbBoxMultiple1 /> <TbBoxMultiple1 />
</ListItemIcon> </ListItemIcon>
<Typography color="textPrimary">Create Order</Typography> <Typography color="textPrimary"> Orders</Typography>
</Grid> </Grid>
} }
/> />
@@ -178,7 +178,7 @@ const HeaderContent = () => {
selected={location.pathname === 'nearle/orders/create'} selected={location.pathname === 'nearle/orders/create'}
onClick={() => { onClick={() => {
// console.log(const location = useLocation();) // console.log(const location = useLocation();)
navigate('nearle/orders/createorders'); navigate('nearle/orders/create/grouporders');
handleClickAway(); handleClickAway();
}} }}
> >
@@ -188,7 +188,7 @@ const HeaderContent = () => {
<ListItemIcon sx={{ mr: 1, fontSize: '20px' }}> <ListItemIcon sx={{ mr: 1, fontSize: '20px' }}>
<GrMultiple /> <GrMultiple />
</ListItemIcon> </ListItemIcon>
<Typography color="textPrimary">Create Group Order</Typography> <Typography color="textPrimary"> Group Orders</Typography>
</Grid> </Grid>
} }
/> />
@@ -224,7 +224,7 @@ const HeaderContent = () => {
<ListItemIcon sx={{ mr: 1, fontSize: '20px' }}> <ListItemIcon sx={{ mr: 1, fontSize: '20px' }}>
<TbUserEdit /> <TbUserEdit />
</ListItemIcon> </ListItemIcon>
<Typography color="textPrimary">Create Customer</Typography> <Typography color="textPrimary"> Customers</Typography>
</Grid> </Grid>
} }
/> />
@@ -273,7 +273,7 @@ const HeaderContent = () => {
</Popper> </Popper>
</Box> </Box>
<Notification /> {/* <Notification /> */}
{/* <Message /> */} {/* <Message /> */}
{/* {!matchesXs && <Profile />} {/* {!matchesXs && <Profile />}

View File

@@ -23,6 +23,7 @@ import {
SettingOutlined SettingOutlined
} from '@ant-design/icons'; } from '@ant-design/icons';
import { Path } from 'leaflet'; import { Path } from 'leaflet';
import { LocationOnOutlined } from '@mui/icons-material';
// icons // icons
const icons = { const icons = {
@@ -56,12 +57,19 @@ const nearle = {
icon: AiOutlineDashboard icon: AiOutlineDashboard
}, },
{ {
id: 'customers', id: 'locations',
title: <FormattedMessage id="Customers" />, title: <FormattedMessage id="Locations" />,
type: 'item', type: 'item',
url: '/nearle/customers', url: '/nearle/locations',
icon: icons.UserOutlined icon: LocationOnOutlined
}, },
// {
// id: 'customers',
// title: <FormattedMessage id="Customers" />,
// type: 'item',
// url: '/nearle/customers',
// icon: icons.UserOutlined
// },
{ {
id: 'reports', id: 'reports',
title: <FormattedMessage id="Reports" />, title: <FormattedMessage id="Reports" />,

View File

@@ -1,6 +1,28 @@
import axios from 'axios'; import axios from 'axios';
const tenid = localStorage.getItem('tenantid'); const tenid = localStorage.getItem('tenantid');
export const fetchOrders = async ({ pageParam = 1, queryKey }) => {
const [, { tenantId, locationId, status, startdate, enddate, searchword, rowsPerPage }] = queryKey;
const url =
`${process.env.REACT_APP_URL}/orders/tenant/getorders/` +
`?tenantid=${tenantId}` +
`&locationid=${locationId}` +
`&status=${status}` +
`&fromdate=${startdate}` +
`&todate=${enddate}` +
`&pageno=${pageParam}` + // 👈 pageParam comes from TanStack
`&pagesize=${rowsPerPage}` +
`&keyword=${searchword}`;
const res = await axios.get(url);
return {
details: res.data.details,
nextPage: res.data.details.length === rowsPerPage ? pageParam + 1 : undefined
// 👈 API must return this flag
};
};
// ==============================|| fetchOrderSummary (orders)||============================== // // ==============================|| fetchOrderSummary (orders)||============================== //
export const fetchOrderSummary = async () => { export const fetchOrderSummary = async () => {
const response = await axios.get(`${process.env.REACT_APP_URL}/orders/getordersummary`); const response = await axios.get(`${process.env.REACT_APP_URL}/orders/getordersummary`);
@@ -38,6 +60,21 @@ export const fetchDeliveryLocationSummary = async () => {
return response.data.details; return response.data.details;
}; };
// ==============================|| getorders (Locations)||============================== //
// fetchOrders.js
export const fetchOrders1 = async ({ pageParam = 1, queryKey }) => {
const [_key, 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}`
);
return {
details: res.data.details,
nextPage: res.data.details.length === rowsPerPage ? pageParam + 1 : undefined
};
};
// ==============================|| fetchAllTenants (clients)||============================== // // ==============================|| fetchAllTenants (clients)||============================== //
@@ -73,7 +110,7 @@ export const fetchCustomersListBySearch = async ({ queryKey }) => {
console.log('fetchCustomersListBySearch', response.data.details); console.log('fetchCustomersListBySearch', response.data.details);
return response.data.details; return response.data.details;
}; };
// ==============================|| fetchOrdersSummary (orders summary)||============================== // // ==============================|| fetchOrdersSummary (rider summary)||============================== //
export const fetchOrdersSummary = async ({ queryKey }) => { export const fetchOrdersSummary = async ({ queryKey }) => {
console.log('queryKey for fetchOrdersSummary', queryKey); console.log('queryKey for fetchOrdersSummary', queryKey);
const [startdate, enddate] = queryKey; const [startdate, enddate] = queryKey;
@@ -95,6 +132,17 @@ export const getreportlocationsummary = async ({ queryKey }) => {
return response.data.details; return response.data.details;
}; };
// ==============================|| getriderlocationreportsummary (orders summary)||============================== //
export const getriderlocationreportsummary = async ({ queryKey }) => {
console.log('queryKey for getriderlocationreportsummary', queryKey);
const [startdate, enddate, locationId] = queryKey;
const response = await axios.get(
`${process.env.REACT_APP_URL}/deliveries/getriderlocationreportsummary/?tenantid=${tenid}&locationid=${locationId}&fromdate=${startdate}&todate=${enddate}`
);
console.log('getriderlocationreportsummary', response.data.details);
return response.data.details;
};
// ==============================|| fetchLocations (orders summary))||============================== // // ==============================|| fetchLocations (orders summary))||============================== //
export const fetchLocations = async () => { export const fetchLocations = async () => {
@@ -107,6 +155,19 @@ export const fetchLocations = async () => {
return updatedLocations; return updatedLocations;
}; };
// ==============================|| gettenantlocations (orders summary))||============================== //
export const gettenantlocations = async ({ queryKey }) => {
const [, searchLocation] = queryKey;
try {
const response = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantlocations?tenantid=${tenid}&keyword=${searchLocation}`);
return response.data?.details || []; // safe fallback
} catch (error) {
console.error('Error fetching tenant locations:', error);
return error.message;
}
};
// ==============================|| fetchDeliverySummary (orders summary)||============================== // // ==============================|| fetchDeliverySummary (orders summary)||============================== //
export const fetchDeliverySummary = async ({ queryKey }) => { export const fetchDeliverySummary = async ({ queryKey }) => {
const [, startdate, enddate, currentStatus, locationId] = queryKey; const [, startdate, enddate, currentStatus, locationId] = queryKey;
@@ -133,11 +194,9 @@ export const fetchAppLocations = async () => {
export const fetchRidersSummary = async ({ queryKey }) => { export const fetchRidersSummary = async ({ queryKey }) => {
console.log('queryKey for fetchRidersSummary', queryKey); console.log('queryKey for fetchRidersSummary', queryKey);
const [id, startdate, enddate] = queryKey; const [tenantid, startdate, enddate] = queryKey;
const response = await axios.get( const response = await axios.get(
id == -1 `${process.env.REACT_APP_URL}/deliveries/getridersummary/?tenantid=${tenantid}&fromdate=${startdate}&todate=${enddate}`
? `${process.env.REACT_APP_URL}/deliveries/getridersummary/?&fromdate=${startdate}&todate=${enddate}`
: `${process.env.REACT_APP_URL}/deliveries/getridersummary/?applocationid=${id}&fromdate=${startdate}&todate=${enddate}`
); );
console.log('fetchRidersSummary', response.data.details); console.log('fetchRidersSummary', response.data.details);
@@ -146,7 +205,7 @@ export const fetchRidersSummary = async ({ queryKey }) => {
// ==============================|| fetchorderdetails (orders detail)||============================== // // ==============================|| fetchorderdetails (orders detail)||============================== //
export const fetchorderdetails = async ({ pageParam = 0, queryKey }) => { export const fetchorderdetails = async ({ pageParam = 0, queryKey }) => {
const [startdate, enddate, currentStatus, locationId] = queryKey; const [startdate, enddate, currentStatus, locationId, searchword] = queryKey;
const limit = 10; const limit = 10;
const pageno = pageParam + 1; // ✅ increment page by 1 each time const pageno = pageParam + 1; // ✅ increment page by 1 each time
@@ -156,7 +215,7 @@ export const fetchorderdetails = async ({ pageParam = 0, queryKey }) => {
process.env.REACT_APP_URL process.env.REACT_APP_URL
}/deliveries/getdeliveries/?tenantid=${tenid}&locationid=${locationId}&fromdate=${startdate}&todate=${enddate}&status=${ }/deliveries/getdeliveries/?tenantid=${tenid}&locationid=${locationId}&fromdate=${startdate}&todate=${enddate}&status=${
currentStatus === 'All' ? '' : currentStatus currentStatus === 'All' ? '' : currentStatus
}&pageno=${pageno}&pagesize=${limit}` }&pageno=${pageno}&pagesize=${limit}&keyword=${searchword}`
); );
const details = response.data.details || []; const details = response.data.details || [];
@@ -206,3 +265,14 @@ export const fetchCount = async ({ queryKey }) => {
return calculateOrderCounts(); return calculateOrderCounts();
}; };
// ==============================|| fetchRidersLogs (RiderLogs)||============================== //
export const fetchRidersLogs = async ({ queryKey }) => {
const [tenantid, startdate] = queryKey;
const riderLogsResponse = await axios.get(
`${process.env.REACT_APP_URL}/partners/getriderlogs/?tenantid=${tenantid}&fromdate=${startdate || ''}`
);
console.log('fetchRidersLogs', riderLogsResponse.data.details);
return riderLogsResponse.data.details;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
import React from 'react';
import { Box, useTheme } from '@mui/material';
import ResponsiveLocationDrawer from './ResponsiveLocationDrawer';
const Locations = () => {
const theme = useTheme();
return (
<Box
sx={{
width: '100%',
height: 'calc(100vh - 144px)', // below global header
overflow: 'hidden',
position: 'relative',
border: '0.1px solid',
borderColor: theme.palette.secondary.light
}}
>
<ResponsiveLocationDrawer />
</Box>
);
};
export default Locations;

View File

@@ -0,0 +1,596 @@
import React, { useState, useEffect, Fragment, useRef } from 'react';
import {
Box,
Drawer,
IconButton,
Toolbar,
Typography,
AppBar,
useMediaQuery,
Divider,
List,
ListItem,
ListItemText,
useTheme,
ListItemAvatar,
Avatar,
Tooltip,
TableCell,
Chip,
Stack,
TableRow,
TableBody,
TableHead,
Table,
TableContainer,
Tabs,
Tab,
CircularProgress
} from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu';
import SearchBar from 'components/nearle_components/SearchBar';
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
import { fetchOrders1, gettenantlocations } from '../api/api';
import Loader from 'components/Loader';
import CircularLoader from 'components/nearle_components/CircularLoader';
import { Empty, Skeleton } from 'antd';
import MainCard from 'components/MainCard';
import AccessTimeIcon from '@mui/icons-material/AccessTime';
import LocalShippingOutlinedIcon from '@mui/icons-material/LocalShippingOutlined';
import { CancelOutlined, CheckCircleOutline } from '@mui/icons-material';
import axios from 'axios';
import dayjs from 'dayjs';
var utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
const drawerWidth = 300;
const ResponsiveLocationDrawer = () => {
const loadMoreRef = useRef();
const containerRef = useRef();
const theme = useTheme();
const tenantid = localStorage.getItem('tenantid');
const isDesktop = useMediaQuery('(min-width:900px)');
const [open, setOpen] = useState(false);
const [selectedLocation, setSelectedLocation] = useState(null);
const [currentStatus, setCurrentStatus] = useState('created');
const [tabvalue, setTabvalue] = useState(0);
const [createdLenght, setCreatedLenght] = useState();
const [pendingLenght, setPendingLenght] = useState();
const [deliveredlenght, setDeliveredlenght] = useState();
const [cancelledLenght, setCancelledLenght] = useState();
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 [searchLocation, setSearchLocation] = useState('');
const [debouncedSearchLocation, setDebouncedSearchLocation] = useState('');
const [searchword, setSearchword] = useState('');
const [debouncedSearchword, setDebouncedSearchword] = useState('');
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedSearchLocation(searchLocation);
}, 400);
return () => clearTimeout(handler);
}, [searchLocation]);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedSearchword(searchword);
}, 400);
return () => clearTimeout(handler);
}, [searchword]);
const statusMap = [
{
label: 'Created',
value: 'created',
count: createdLenght,
icon: <AccessTimeIcon color="primary" fontSize="small" />
},
{
label: 'Pending',
value: 'pending',
count: pendingLenght,
icon: <LocalShippingOutlinedIcon color="primary" fontSize="small" />
},
{
label: 'Delivered',
value: 'delivered',
count: deliveredlenght,
icon: <CheckCircleOutline color="primary" fontSize="small" />
},
{
label: 'Cancelled',
value: 'cancelled',
count: cancelledLenght,
icon: <CancelOutlined color="primary" fontSize="small" />
}
];
const handleChangetab = (e, i) => {
setSearchword('');
setRowsPerPage(10);
setTabvalue(i);
setCurrentStatus(statusMap[i].value);
setPage(0);
};
const {
data: locations,
isLoading: locationIsLoading,
isError: locationIsError,
error: locationError
} = useQuery({
queryKey: ['locations', debouncedSearchLocation],
queryFn: gettenantlocations
});
useEffect(() => {
if (!searchLocation) locations?.length > 0 ? setSelectedLocation(locations[0]) : null;
}, [locations]);
const {
data: ordersData,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
isLoading,
error
} = useInfiniteQuery({
queryKey: [
'orders',
tenantid,
selectedLocation?.locationid ?? null, // stable
currentStatus,
startdate,
enddate,
debouncedSearchLocation,
rowsPerPage
],
queryFn: fetchOrders1,
getNextPageParam: (lastPage) => lastPage.nextPage
});
const rows = ordersData?.pages?.flatMap((page) => page.details) || [];
useEffect(() => {
if (!hasNextPage) return;
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
fetchNextPage();
}
},
{
root: document.querySelector('.MuiTableContainer-root'), // 👈 or explicitly TableContainer
rootMargin: '0px',
threshold: 1.0
}
);
if (loadMoreRef.current) observer.observe(loadMoreRef.current);
return () => {
if (loadMoreRef.current) observer.unobserve(loadMoreRef.current);
};
}, [hasNextPage, fetchNextPage]);
const handleScroll = (event) => {
const { scrollTop, scrollHeight, clientHeight } = event.currentTarget;
if (scrollTop + clientHeight >= scrollHeight - 50) {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
}
};
const fetchorderscount = async () => {
setLoading(true);
try {
await axios
.get(
`${process.env.REACT_APP_URL}/orders/getordersummary/?tenantid=${tenantid}&locationid=${selectedLocation?.locationid}&fromdate=${startdate}&todate=${enddate}`
)
.then((res) => {
console.log('fetchorderscount', res.data.details);
setCreatedLenght(res.data.details.created);
setPendingLenght(res.data.details.pending);
setDeliveredlenght(res.data.details.delivered);
setCancelledLenght(res.data.details.cancelled);
tabvalue === 0 && setPageCount(res.data.details.created);
tabvalue === 1 && setPageCount(res.data.details.pending);
tabvalue === 2 && setPageCount(res.data.details.delivered);
tabvalue === 3 && setPageCount(res.data.details.cancelled);
setLoading(false);
})
.catch((err) => {
console.log(err);
setLoading(false);
});
} catch (err) {
console.log(err);
setLoading(false);
}
};
useEffect(() => {
fetchorderscount();
}, [currentStatus, selectedLocation, startdate, enddate]);
useEffect(() => {
setOpen(isDesktop);
}, [isDesktop]);
const toggleDrawer = () => setOpen(!open);
const errMessage = locationIsError ? `${locationError.message}` : null;
useEffect(() => {
errMessage && console.log(errMessage);
}, [errMessage]);
return (
<React.Fragment>
{locationIsLoading && (
<>
<Loader /> <CircularLoader />
</>
)}
<Box sx={{ display: 'flex', width: '100%', height: '100%', position: 'relative' }}>
{/* ---------------- LOCAL DRAWER ---------------- */}
<Drawer
variant={isDesktop ? 'persistent' : 'temporary'}
open={open}
onClose={() => !isDesktop && toggleDrawer()}
ModalProps={{ keepMounted: true }}
sx={{
'& .MuiDrawer-paper': {
width: drawerWidth,
boxSizing: 'border-box',
position: 'absolute',
left: 0,
top: 0,
height: '100%',
overflowY: 'auto',
transition: 'transform 0.35s ease-in-out',
zIndex: 10,
/* vertical scrollbar */
'&::-webkit-scrollbar:vertical': {
width: '7px',
opacity: 0,
transition: 'opacity 0.3s'
},
/* horizontal scrollbar */
'&::-webkit-scrollbar:horizontal': {
height: '6px', // thinner horizontal bar
opacity: 0,
transition: 'opacity 0.3s'
},
/* show scrollbar when hovering drawer */
'&:hover::-webkit-scrollbar': {
opacity: 1
},
/* thumb styling */
'&::-webkit-scrollbar-thumb': {
backgroundColor: theme.palette.primary.main,
borderRadius: '8px'
},
'&::-webkit-scrollbar-thumb:hover': {
backgroundColor: theme.palette.primary.dark
},
/* track styling */
'&::-webkit-scrollbar-track': {
backgroundColor: theme.palette.primary.lighter
}
}
}}
>
<Box sx={{ position: 'sticky', top: 0, zIndex: 11, border: 'none' }}>
<SearchBar
value={searchLocation}
placeholder="Search Location"
onChange={(e) => setSearchLocation(e.target.value)}
sx={{
width: 'auto',
height: 60,
bgcolor: theme.palette.primary.lighter,
'& .MuiOutlinedInput-notchedOutline': {
border: 'none',
borderBottom: '1px solid ',
borderColor: theme.palette.secondary.light
}
}}
/>
</Box>
<List sx={{ mt: -1 }}>
{locations?.map((row, index) => (
<React.Fragment key={index}>
<ListItem
sx={{
cursor: 'pointer',
bgcolor: row.locationid == selectedLocation?.locationid ? theme.palette.secondary[200] : 'none',
'&:hover': {
bgcolor: theme.palette.secondary.lighter
}
}}
onClick={() => {
setSelectedLocation(row);
}}
>
<ListItemAvatar>
<Avatar
sx={{
bgcolor: 'primary.main', // background color
color: 'white' // text color
}}
>
{row.locationname[0].toUpperCase()}
</Avatar>{' '}
</ListItemAvatar>
<ListItemText primary={row.locationname} secondary={row.suburb} />
</ListItem>
<Divider />
</React.Fragment>
))}
</List>
</Drawer>
{/* -------------- LOCAL PAGE APPBAR -------------- */}
<AppBar
elevation={0}
position="absolute"
sx={{
top: 0,
left: open && isDesktop ? `${drawerWidth}px` : 0,
width: open && isDesktop ? `calc(100% - ${drawerWidth}px)` : '100%',
transition: 'left 0.3s ease, width 0.3s ease',
zIndex: 1100, // BELOW drawer, ABOVE content
backgroundColor: theme.palette.primary.lighter
}}
>
<Toolbar>
<Stack
sx={{ width: '100%' }}
display={'flex'}
flexDirection={'row'}
alignItems={'center'}
justifyContent={'space-between'}
flexWrap={'wrap'}
>
<Stack display={'flex'} flexDirection={'row'} alignItems={'center'}>
<IconButton color="primary" onClick={toggleDrawer} sx={{ mr: 1 }}>
<MenuIcon />
</IconButton>
<Typography variant="h5" color={'primary'} sx={{ whiteSpace: 'nowrap', ml: 2 }}>
{selectedLocation?.locationname}
</Typography>
</Stack>
<Stack flexGrow={1} sx={{ mx: { xs: 0, custom600: 3 } }}>
<SearchBar
value={searchword}
placeholder={'Search Order Details'}
onChange={(e) => setSearchword(e.target.value)}
sx={{
width: 'auto',
height: 40,
bgcolor: theme.palette.primary.lighter,
'& .MuiOutlinedInput-notchedOutline': {
border: 'none',
borderBottom: '1px solid ',
borderColor: theme.palette.secondary.light
}
}}
/>
</Stack>
</Stack>
</Toolbar>
</AppBar>
{/* ---------------- PAGE SCROLLABLE CONTENT ---------------- */}
<Box
sx={{
flexGrow: 1,
overflow: 'auto',
pt: '64px', // Height of AppBar
pl: isDesktop && open ? `${drawerWidth}px` : 0,
transition: 'padding-left 0.3s ease',
mt: -1
}}
>
<Stack
display={'flex'}
flexDirection={'row'}
justifyContent={'space-between'}
alignItems={'center'}
flexWrap={'wrap-reverse'}
gap={2}
sx={{
border: '1px solid ',
borderBottom: 0,
borderColor: 'bg.main',
p: 1.5
}}
>
{/* Tabs Wrapper */}
<Tabs value={tabvalue} onChange={handleChangetab} variant="scrollable" scrollButtons="auto" allowScrollButtonsMobile>
{statusMap.map((item, index) => (
<Tab
key={index}
label={
<Stack direction="row" alignItems="center" spacing={1}>
{item.icon}
<span>{item.label}</span>
<Chip label={item.count} color="primary" variant="light" size="small" />
</Stack>
}
/>
))}
</Tabs>
</Stack>
<MainCard
content={false}
sx={{
overflow: 'hidden',
height: 'calc(100vh - 200px)', // adjust as needed
display: 'flex',
flexDirection: 'column'
}}
>
<Fragment>
{/* Scrollable table container */}
<TableContainer
onScroll={handleScroll}
ref={containerRef}
sx={{
width: '100%',
flex: 1,
overflow: 'auto',
borderBottom: 1,
maxHeight: 'calc(100vh - 225px)',
borderColor: 'divider',
'&::-webkit-scrollbar': { width: '12px' },
'&::-webkit-scrollbar-thumb': {
backgroundColor: theme.palette.primary.main,
borderRadius: '8px'
},
'&::-webkit-scrollbar-thumb:hover': {
backgroundColor: theme.palette.primary.dark
},
'&::-webkit-scrollbar-track': {
backgroundColor: theme.palette.primary.lighter
}
}}
>
<Table stickyHeader>
{/* HEADER */}
<TableHead>
<TableRow>
<TableCell sx={{ backgroundColor: theme.palette.secondary.light, position: 'sticky !important' }}>S.No</TableCell>
<TableCell sx={{ backgroundColor: theme.palette.secondary.light, position: 'sticky !important' }}>Orders</TableCell>
<TableCell sx={{ backgroundColor: theme.palette.secondary.light, position: 'sticky !important' }}>Pickup</TableCell>
<TableCell sx={{ backgroundColor: theme.palette.secondary.light, position: 'sticky !important' }}>Drop</TableCell>
<TableCell sx={{ backgroundColor: theme.palette.secondary.light, position: 'sticky !important' }}>Notes</TableCell>
<TableCell sx={{ backgroundColor: theme.palette.secondary.light, position: 'sticky !important' }}>Status</TableCell>
</TableRow>
</TableHead>
{/* BODY */}
<TableBody>
{/* LOADING STATE */}
{loading &&
[...Array(10)].map((_, index) => (
<TableRow key={index}>
{[...Array(6)].map((__, i) => (
<TableCell key={i}>
<Skeleton animation="wave" />
</TableCell>
))}
</TableRow>
))}
{/* EMPTY STATE */}
{!loading && rows?.length === 0 && (
<TableRow>
<TableCell colSpan={6} sx={{ minWidth: '100%', height: 500 }} align="center">
<Empty description={'No Orders'} />
</TableCell>
</TableRow>
)}
{/* DATA ROWS */}
{!loading &&
rows?.map((row, index) => (
<TableRow key={index} sx={{ cursor: 'pointer' }}>
<TableCell>{page * rowsPerPage + index + 1}</TableCell>
{/* Order Info */}
<TableCell>
<Typography variant="body2" noWrap>
{row.orderid}
</Typography>
<Typography variant="caption" noWrap>
{dayjs(row.deliverydate).utc().format('DD/MM/YYYY')}
</Typography>
<Typography variant="caption" noWrap>
{dayjs(row.deliverydate).utc().format('hh:mm A')}
</Typography>
</TableCell>
{/* Pickup */}
<TableCell>
<Stack direction="row" spacing={1}>
<Avatar sx={{ width: 25, height: 25 }} />
<Stack>
<Typography variant="caption">{row.pickupcustomer}</Typography>
<Typography variant="caption">{row.pickupcontactno}</Typography>
<Tooltip title={row.pickupaddress}>
<Typography variant="caption">{row.pickupsuburb || row.pickupaddress.slice(0, 20)}</Typography>
</Tooltip>
</Stack>
</Stack>
</TableCell>
{/* Drop */}
<TableCell>
<Stack direction="row" spacing={1}>
<Avatar sx={{ width: 25, height: 25 }} />
<Stack>
<Typography variant="caption">{row.deliverycustomer}</Typography>
<Typography variant="caption">{row.deliverycontactno}</Typography>
<Tooltip title={row.deliveryaddress}>
<Typography variant="caption">{row.deliverysuburb || row.deliveryaddress.slice(0, 20)}</Typography>
</Tooltip>
</Stack>
</Stack>
</TableCell>
{/* Notes */}
<TableCell>{row.ordernotes}</TableCell>
{/* Status */}
<TableCell>
<Stack direction="row" spacing={1}>
{row.orderstatus === 'pending' && <Chip label="Pending" color="warning" size="small" />}
{row.orderstatus === 'confirmed' && <Chip label="Confirmed" color="success" size="small" />}
{row.orderstatus === 'cancelled' && <Chip label="Cancelled" color="error" size="small" />}
{row.orderstatus === 'delivered' && <Chip label="Completed" color="primary" size="small" />}
{row.orderstatus === 'processing' && <Chip label="Processing" color="primary" size="small" />}
{row.orderstatus === 'ready' && <Chip label="Accepted" color="info" size="small" />}
{row.orderstatus === 'active' && <Chip label="Picked" color="info" size="small" />}
{row.orderstatus === 'closed' && <Chip label="Closed" color="info" size="small" />}
{row.orderstatus === 'created' && <Chip label="Created" color="secondary" size="small" />}
</Stack>
</TableCell>
</TableRow>
))}
{rows?.length != 0 && (
<TableRow>
<TableCell colSpan={6} rowSpan={3}>
<div ref={loadMoreRef} style={{ height: 40, textAlign: 'center' }}>
{isFetchingNextPage ? <CircularProgress /> : hasNextPage ? <CircularProgress /> : 'No More Orders'}
</div>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
</Fragment>
</MainCard>
</Box>
</Box>
</React.Fragment>
);
};
export default ResponsiveLocationDrawer;

View File

@@ -132,6 +132,7 @@ const Login = () => {
}); });
setUsername(''); setUsername('');
setPassword(''); setPassword('');
localStorage.setItem('tenantname', res.data.details.tenantname);
localStorage.setItem('firstname', res.data.details.tenantname); localStorage.setItem('firstname', res.data.details.tenantname);
localStorage.setItem('authname', res.data.details.authname); localStorage.setItem('authname', res.data.details.authname);
localStorage.setItem('appuserid', res.data.details.userid); localStorage.setItem('appuserid', res.data.details.userid);

View File

@@ -0,0 +1,78 @@
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
// distance function (same)
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 center = [11.015181, 76.953682];
const riders = [
{ id: 1, lat: 11.04362, lng: 76.924667 },
{ id: 2, lat: 11.00988, lng: 76.949966 },
{ id: 3, lat: 11.020983, lng: 76.966331 }
];
export default function RidersPinPointOSM() {
const sortedRiders = riders
.map((r) => ({
...r,
distance: distance(center[0], center[1], r.lat, r.lng)
}))
.sort((a, b) => a.distance - b.distance);
// purple center marker
const centerIcon = L.icon({
iconUrl: 'https://maps.google.com/mapfiles/ms/icons/purple-dot.png',
iconSize: [32, 32]
});
// basic numbered marker icon
const createMarkerIcon = (number) =>
L.divIcon({
className: 'custom-marker',
html: `
<div style="
background:#007bff;
color:white;
width:28px;
height:28px;
border-radius:50%;
display:flex;
align-items:center;
justify-content:center;
font-weight:bold;
border:2px solid white;
">
${number}
</div>
`,
iconSize: [30, 30],
iconAnchor: [15, 15]
});
return (
<MapContainer center={center} zoom={14} style={{ height: '300px', width: '100%' }}>
{/* OSM tiles */}
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
{/* Purple center marker */}
<Marker position={center} icon={centerIcon} />
{/* Sorted rider markers */}
{sortedRiders.map((r, index) => (
<Marker key={r.id} position={[r.lat, r.lng]} icon={createMarkerIcon(index + 1)}>
<Popup>Rider {index + 1}</Popup>
</Marker>
))}
</MapContainer>
);
}

View File

@@ -940,7 +940,7 @@ const Createorder1 = () => {
sendnotifications(); sendnotifications();
} }
navigate('/orders'); navigate('/nearle/orders');
} else { } else {
opentoast('Something went wrong, Cannot create order', 'warning'); opentoast('Something went wrong, Cannot create order', 'warning');
} }

View File

@@ -16,6 +16,7 @@ var utc = require('dayjs/plugin/utc');
dayjs.extend(utc); dayjs.extend(utc);
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import { GoogleMap, LoadScript, Marker } from '@react-google-maps/api';
import { import {
FormControl, FormControl,
@@ -43,9 +44,12 @@ import {
TableBody, TableBody,
TableRow, TableRow,
Paper, Paper,
TableHead TableHead,
Box
} from '@mui/material'; } from '@mui/material';
import CircularLoader from 'components/nearle_components/CircularLoader'; import CircularLoader from 'components/nearle_components/CircularLoader';
// import RidersPinPointOSM from './RidersPinPointOSM';
import RidersPinPoint from './ridersPinPoint';
const MultipleOrders = () => { const MultipleOrders = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -62,7 +66,7 @@ const MultipleOrders = () => {
const [basePrice, setBasePrice] = useState(0); const [basePrice, setBasePrice] = useState(0);
const [pricePerKm, setPricePerKm] = useState(0); const [pricePerKm, setPricePerKm] = useState(0);
const [minKm, setMinKm] = useState(0); const [minKm, setMinKm] = useState(0);
const [pickCust, setPickCust] = useState({}); const [pickCust, setPickCust] = useState(null);
const [dropCust, setDropCust] = useState([]); const [dropCust, setDropCust] = useState([]);
const [isCustomerOpen, setIsCustomerOpen] = useState(false); const [isCustomerOpen, setIsCustomerOpen] = useState(false);
const [searchCustList, setSearchCustList] = useState(''); const [searchCustList, setSearchCustList] = useState('');
@@ -77,9 +81,10 @@ const MultipleOrders = () => {
const [totaldist, settotaldist] = useState(0); const [totaldist, settotaldist] = useState(0);
const [totalAmt, settotalAmt] = useState(0); const [totalAmt, settotalAmt] = useState(0);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [showMap, setShowMap] = useState(false);
useEffect(() => { useEffect(() => {
console.log('dropCust', dropCust); dropCust && console.log('dropCust', dropCust);
}, [dropCust]); }, [dropCust]);
// =============================================== || opentoast || =============================================== // =============================================== || opentoast || ===============================================
@@ -180,7 +185,7 @@ const MultipleOrders = () => {
const calculateTotal = () => { const calculateTotal = () => {
let a1 = 0; let a1 = 0;
let a2 = 0; let a2 = 0;
dropCust.map((customer) => { dropCust?.map((customer) => {
a1 += customer.distance; a1 += customer.distance;
a2 += customer.totalcharge; a2 += customer.totalcharge;
}); });
@@ -188,7 +193,7 @@ const MultipleOrders = () => {
settotalAmt(a2); settotalAmt(a2);
}; };
useEffect(() => { useEffect(() => {
calculateTotal(); dropCust && calculateTotal();
}, [dropCust]); }, [dropCust]);
// ========================================================= || handleCheckboxChange || ========================================================= // ========================================================= || handleCheckboxChange || =========================================================
@@ -360,9 +365,7 @@ const MultipleOrders = () => {
useEffect(() => { useEffect(() => {
console.log('pickCust', pickCust); console.log('pickCust', pickCust);
}, [pickCust]); }, [pickCust]);
useEffect(() => {
console.log('dropCust', dropCust);
}, [dropCust]);
// ==================================================== || fetchtenantinfo || ==================================================== // ==================================================== || fetchtenantinfo || ====================================================
const fetchtenantinfo = async () => { const fetchtenantinfo = async () => {
setLoading(true); setLoading(true);
@@ -424,9 +427,9 @@ const MultipleOrders = () => {
setLoading(false); setLoading(false);
}); });
}; };
// =============================================== || createorders || =============================================== // =============================================== || creategrouporders || ===============================================
const createorders = async () => { const creategrouporders = async () => {
const arr = dropCust.map((customer) => ({ const arr = dropCust?.map((customer) => ({
applocationid: pickCust.applocationid, applocationid: pickCust.applocationid,
cancellled: '', cancellled: '',
// categoryid: +tenant.categoryid, // categoryid: +tenant.categoryid,
@@ -500,7 +503,7 @@ const MultipleOrders = () => {
// notifyadmin(admintoken); // notifyadmin(admintoken);
sendnotifications(); sendnotifications();
} }
navigate('/orders'); navigate('/nearle/orders');
} else { } else {
opentoast(res.data.message, 'warning'); opentoast(res.data.message, 'warning');
} }
@@ -515,36 +518,38 @@ const MultipleOrders = () => {
} }
console.log(arr); console.log(arr);
}; };
return ( return (
<> <>
{loading && <Loader />} {loading && <Loader />}
<Grid {/* <RidersPinPointOSM /> */}
container <Grid container sx={{ mb: 2 }}>
spacing={3} <Grid item xs={12} sm={3} md={6}>
sx={{ <Stack>
position: 'sticky', <Typography variant="h3" whiteSpace="nowrap">
top: '60px', Group Orders
bgcolor: theme.palette.background.default, </Typography>
zIndex: 100, </Stack>
display: 'flex', </Grid>
flexDirection: 'column', <Grid item xs={12} sm={9} md={6}>
justifyContent: 'start', <Stack
alignItems: 'center', sx={{}}
spacing: 5 width={'100%'}
}} direction="row"
alignItems="center"
spacing={2}
justifyContent={'flex-end'}
flexWrap={{ xs: 'wrap', custom550: 'nowrap' }}
gap={2}
> >
<Grid item xs={12} sx={{ width: '100%', mt: -1 }}> {/* Business Location */}
<Stack direction={'row'} alignItems={'center'} justifyContent={'space-between'}> <Stack sx={{ width: '100%' }}>
<Typography variant="h3"> Group Orders</Typography> {tenantLocations?.length === 1 ? (
{tenantLocations.length == 1 ? (
<TextField <TextField
// disabled={!isAppLocation || !isClient} label="Business Location"
variant="outlined"
fullWidth fullWidth
label={'Business Location'}
value={tenantLocations[0].locationname}
focused focused
sx={{ width: '350px' }} value={tenantLocations[0]?.locationname}
InputProps={{ InputProps={{
style: { color: theme.palette.primary.main }, style: { color: theme.palette.primary.main },
startAdornment: ( startAdornment: (
@@ -557,59 +562,49 @@ const MultipleOrders = () => {
) : ( ) : (
<Autocomplete <Autocomplete
fullWidth fullWidth
// disabled={!isAppLocation || !isClient}
id="combo-box-demo"
options={tenantLocations || []} options={tenantLocations || []}
getOptionLabel={(option) => `${option.locationname} (${option.suburb})` || ''} getOptionLabel={(option) => `${option.locationname} (${option.suburb})`}
renderInput={(params) => <TextField {...params} label="Select Business Locations" color="primary" />}
sx={{ width: '350px' }}
onChange={(event, value, reason) => { onChange={(event, value, reason) => {
if (value) { if (value) {
console.log('Business Locations', value);
setTid(value.tenantid); setTid(value.tenantid);
setIsLocation(true); setIsLocation(true);
setPickCust(value); setPickCust(value);
} }
if (reason == 'clear') { if (reason === 'clear') setIsLocation(false);
setIsLocation(false);
}
}} }}
renderInput={(params) => <TextField {...params} label="Select Business Location" color="primary" fullWidth />}
/> />
)} )}
</Stack> </Stack>
</Grid>
{/* ===================================================== || Pickup || ===================================================== */} {/* Date Picker */}
<Grid item xs={12} sx={{ width: '100%' }}> <Stack sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<MainCard <LocalizationProvider dateAdapter={AdapterDayjs}>
sx={{ height: '100%' }}
title={'Pickup'}
secondary={
<LocalizationProvider dateAdapter={AdapterDayjs} sx={{}}>
<DatePicker <DatePicker
format="DD-MM-YYYY" format="DD-MM-YYYY"
disablePast
value={dayjs(startdate)}
sx={{ width: 150 }}
onChange={(e) => { onChange={(e) => {
let dateres11 = dayjs().diff(dayjs(`${dayjs(e).format('YYYY-MM-DD')}`), 'd'); let diff = dayjs().diff(dayjs(dayjs(e).format('YYYY-MM-DD')), 'd');
console.log('dateres11');
console.log(dateres11);
if (dateres11 <= 0) { if (diff <= 0) {
console.log('startdate', e);
setStartdate(e); setStartdate(e);
let arr = []; let arr = [];
timeslotarr.map((val) => { timeslotarr.forEach((val) => {
if (dayjs().diff(dayjs(`${dayjs(e).format('MM-DD-YYYY')} ${dayjs(val).format('HH:mm:ss')}`), 'm') <= 0) { if (dayjs().diff(dayjs(`${dayjs(e).format('MM-DD-YYYY')} ${dayjs(val).format('HH:mm:ss')}`), 'm') <= 0) {
arr.push(val); arr.push(val);
} }
}); });
if (arr[0]) { if (arr[0]) {
setOrderarr([ setOrderarr([
{ {
sno: 1, sno: 1,
address: '', address: '',
customerid: '', customerid: '',
deliverytime: dayjs(arr[0]) || '', deliverytime: dayjs(arr[0]),
deliverylocationid: '', deliverylocationid: '',
clientname: '', clientname: '',
contactno: '', contactno: '',
@@ -621,38 +616,39 @@ const MultipleOrders = () => {
setOrderarr([]); setOrderarr([]);
} }
} else { } else {
setAlertmessage('choose Upcoming Date');
opentoast('choose Upcoming Date', 'warning'); opentoast('choose Upcoming Date', 'warning');
setStartdate(NaN); setStartdate(NaN);
} }
}} }}
value={dayjs(startdate)}
sx={{ width: '100%' }}
disablePast
/> />
</LocalizationProvider> </LocalizationProvider>
} </Stack>
> </Stack>
<TableContainer component={Paper}> </Grid>
</Grid>
{/* ===================================================== || Pickup || ===================================================== */}
{pickCust && (
<TableContainer component={Paper} sx={{ mb: 2 }}>
<Table sx={{ minWidth: 650 }} aria-label="simple table"> <Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell>Tenant</TableCell> <TableCell>Pickup Location</TableCell>
<TableCell>Address</TableCell> <TableCell>Address</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
<TableRow> <TableRow>
<TableCell>{pickCust.locationname}</TableCell> <TableCell>{pickCust?.locationname}</TableCell>
<TableCell>{pickCust.address}</TableCell> <TableCell>{pickCust?.address}</TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
</MainCard> )}
</Grid>
{/* ===================================================== || Drop || ===================================================== */} {/* ===================================================== || Drop || ===================================================== */}
<Grid item xs={12} sx={{ width: '100%', mt: -2 }}>
<MainCard <MainCard
sx={{ height: '100%' }} sx={{ height: '100%' }}
title={`Drop (${dropCust?.length || 0})`} title={`Drop (${dropCust?.length || 0})`}
@@ -692,7 +688,14 @@ const MultipleOrders = () => {
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{dropCust.map((customer, index) => ( {!dropCust && (
<TableRow>
<TableCell colSpan={6}>
<Empty description={' Drop Customers Not Selected'} />
</TableCell>
</TableRow>
)}
{dropCust?.map((customer, index) => (
<TableRow key={index}> <TableRow key={index}>
<TableCell>{index + 1}</TableCell> <TableCell>{index + 1}</TableCell>
<TableCell>{customer.firstname}</TableCell> <TableCell>{customer.firstname}</TableCell>
@@ -709,7 +712,7 @@ const MultipleOrders = () => {
</TableCell> </TableCell>
</TableRow> </TableRow>
))} ))}
{dropCust.length != 0 && ( {dropCust?.length != 0 && (
<TableRow> <TableRow>
<TableCell> <TableCell>
<Typography variant="h5">Total</Typography> <Typography variant="h5">Total</Typography>
@@ -729,10 +732,13 @@ const MultipleOrders = () => {
</Table> </Table>
</TableContainer> </TableContainer>
</MainCard> </MainCard>
</Grid>
<Grid item xs={12} sx={{ width: '100%', mt: -2 }}> {/* ================================================= || Riders Map || ================================================= */}
{/* {showMap && dropCust.length >= 1 && <RidersPinPoint pickCust={pickCust} dropCust={dropCust} />} */}
{/* ================================================= || Notes || ================================================= */} {/* ================================================= || Notes || ================================================= */}
{dropCust && (
<MainCard sx={{ mt: 2 }} title={'Notes'}> <MainCard sx={{ mt: 2 }} title={'Notes'}>
<Grid container> <Grid container>
<Grid item xs={12}> <Grid item xs={12}>
@@ -749,13 +755,13 @@ const MultipleOrders = () => {
</Grid> </Grid>
<Stack direction="row" justifyContent={'end'} sx={{ mt: 2, width: '100%' }}> <Stack direction="row" justifyContent={'end'} sx={{ mt: 2, width: '100%' }}>
<Button <Button
disabled={dropCust.length == 0} disabled={dropCust?.length == 0}
size="medium" size="medium"
variant="outlined" variant="outlined"
onClick={() => { onClick={() => {
setLoading(true); setLoading(true);
setBtnLoading(true); setBtnLoading(true);
createorders(); creategrouporders();
setTimeout(() => { setTimeout(() => {
setLoading(false); setLoading(false);
setBtnLoading(false); setBtnLoading(false);
@@ -773,8 +779,8 @@ const MultipleOrders = () => {
</Stack> </Stack>
</Grid> </Grid>
</MainCard> </MainCard>
</Grid> )}
</Grid>
{/* ============================================= || saved address Dialog || ============================================= */} {/* ============================================= || saved address Dialog || ============================================= */}
<Dialog <Dialog
open={isCustomerOpen} open={isCustomerOpen}
@@ -787,7 +793,7 @@ const MultipleOrders = () => {
{isLoading && <CircularLoader />} {isLoading && <CircularLoader />}
<DialogTitle sx={{ bgcolor: theme.palette.primary.main, color: 'white' }}> <DialogTitle sx={{ bgcolor: theme.palette.primary.main, color: 'white' }}>
<Stack> <Stack>
<Typography variant="h4"> {`Select Drop Customers (${dropCust.length || 0})`}</Typography> <Typography variant="h4"> {`Select Drop Customers (${dropCust?.length || 0})`}</Typography>
<FormControl <FormControl
sx={{ sx={{
width: '100%', width: '100%',
@@ -842,7 +848,7 @@ const MultipleOrders = () => {
<FormControlLabel <FormControlLabel
control={ control={
<Checkbox <Checkbox
checked={dropCust.some((cust) => cust.customerid === customer.customerid)} // Set the checked state of the checkbox based on whether the customer is in `dropCust` checked={dropCust?.some((cust) => cust.customerid === customer.customerid)} // Set the checked state of the checkbox based on whether the customer is in `dropCust`
onChange={(event) => handleCheckboxChange(event, customer)} onChange={(event) => handleCheckboxChange(event, customer)}
/> />
} }
@@ -866,19 +872,22 @@ const MultipleOrders = () => {
<Divider /> <Divider />
<DialogActions sx={{ p: 2.5 }}> <DialogActions sx={{ p: 2.5 }}>
<Button <Button
color={dropCust.length !== 0 ? 'primary' : 'error'} color={dropCust?.length !== 0 ? 'primary' : 'error'}
variant="outlined" variant="outlined"
sx={{ sx={{
'&:hover': { '&:hover': {
bgcolor: dropCust.length !== 0 ? theme.palette.primary.main : theme.palette.error.main, bgcolor: dropCust?.length !== 0 ? theme.palette.primary.main : theme.palette.error.main,
color: 'white' color: 'white'
} }
}} }}
onClick={() => { onClick={() => {
setIsCustomerOpen(false); setIsCustomerOpen(false);
{
dropCust?.length !== 0 && setShowMap(true);
}
}} }}
> >
{dropCust.length !== 0 ? 'Continue' : 'Close'} {dropCust?.length !== 0 ? 'Continue' : 'Close'}
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>

View File

@@ -10,10 +10,10 @@ import axios from 'axios';
import HoverSocialCard from 'components/cards/statistics/HoverSocialCard'; import HoverSocialCard from 'components/cards/statistics/HoverSocialCard';
import { useTheme } from '@mui/material/styles'; import { useTheme } from '@mui/material/styles';
import MyLocationIcon from '@mui/icons-material/MyLocation'; import MyLocationIcon from '@mui/icons-material/MyLocation';
import { CalendarMonth, CancelOutlined, CheckCircleOutline } from '@mui/icons-material';
import { import {
Avatar, Avatar,
Box,
Button, Button,
Grid, Grid,
Tabs, Tabs,
@@ -29,35 +29,37 @@ import {
Dialog, Dialog,
TableRow, TableRow,
DialogContent, DialogContent,
DialogTitle,
Tooltip, Tooltip,
FormControl, FormControl,
OutlinedInput, OutlinedInput,
InputAdornment, InputAdornment,
Skeleton, Skeleton,
Autocomplete, Autocomplete,
TextField TextField,
CircularProgress
} from '@mui/material'; } from '@mui/material';
import { SearchOutlined, CloseOutlined } from '@ant-design/icons'; import { SearchOutlined, CloseOutlined } from '@ant-design/icons';
import ClearIcon from '@mui/icons-material/Clear'; import ClearIcon from '@mui/icons-material/Clear';
import { addDays, addMonths, addWeeks, endOfMonth, endOfWeek, startOfMonth, startOfWeek } from 'date-fns';
import { DateRangePicker } from 'mui-daterange-picker';
import TableContainer from '@mui/material/TableContainer'; import TableContainer from '@mui/material/TableContainer';
import TablePagination from '@mui/material/TablePagination'; import TablePagination from '@mui/material/TablePagination';
import TableSortLabel from '@mui/material/TableSortLabel';
import { visuallyHidden } from '@mui/utils';
import Loader from 'components/Loader'; import Loader from 'components/Loader';
import { FilterList } from '@mui/icons-material'; // import { FilterList } from '@mui/icons-material';
import { Outlet } from 'react-router'; import { useHotkeyFocus } from 'components/nearle_components/useHotkeyFocus';
import DateFilterDialog from 'components/nearle_components/DateFilterDialog';
import MainCard from 'components/MainCard';
import AccessTimeIcon from '@mui/icons-material/AccessTime';
import LocalShippingOutlinedIcon from '@mui/icons-material/LocalShippingOutlined';
import CircularLoader from 'components/nearle_components/CircularLoader';
import { useInfiniteQuery } from '@tanstack/react-query';
const Orders = () => { const Orders = () => {
const tid = localStorage.getItem('tenantid'); const tid = localStorage.getItem('tenantid');
const tenId = localStorage.getItem('tenantid'); const tenId = localStorage.getItem('tenantid');
const loadMoreRef = useRef();
const containerRef = useRef();
const [page, setPage] = React.useState(0); const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(10); const [rowsPerPage, setRowsPerPage] = React.useState(10);
const [pageCount, setPageCount] = React.useState(); 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 [percentage1, setPercentage1] = useState('0'); const [percentage1, setPercentage1] = useState('0');
const [percentage2, setPercentage2] = useState('0'); const [percentage2, setPercentage2] = useState('0');
const [percentage3, setPercentage3] = useState('0'); const [percentage3, setPercentage3] = useState('0');
@@ -67,14 +69,10 @@ const Orders = () => {
const [uncoveredorders, setUncoveredorders] = useState(''); const [uncoveredorders, setUncoveredorders] = useState('');
const [cancelled, setCancelled] = useState(''); const [cancelled, setCancelled] = useState('');
const [created, setCreated] = useState(''); const [created, setCreated] = useState('');
const [tabstatus, setTabstatus] = useState('Created'); const [loading, setLoading] = useState(false);
const [loading, setLoading] = useState(true);
const theme = useTheme(); const theme = useTheme();
let [rows, setRows] = useState([]);
const [tabvalue, setTabvalue] = useState(0); const [tabvalue, setTabvalue] = useState(0);
const [open, setOpen] = useState(false); const [tabstatus, setTabstatus] = useState('Created');
const [datestatus, setDatestatus] = useState('Today');
const [searchword, setSearchword] = useState('');
const [currentStatus, setCurrentStatus] = useState('created'); const [currentStatus, setCurrentStatus] = useState('created');
const [createdLenght, setCreatedLenght] = useState(); const [createdLenght, setCreatedLenght] = useState();
const [pendingLenght, setPendingLenght] = useState(); const [pendingLenght, setPendingLenght] = useState();
@@ -84,54 +82,60 @@ const Orders = () => {
const [orderheaderid, setOrderheaderid] = useState(''); const [orderheaderid, setOrderheaderid] = useState('');
const [locationId, setLocationId] = useState(0); const [locationId, setLocationId] = useState(0);
const [locoName, setLocoName] = useState('Select Location'); const [locoName, setLocoName] = useState('Select Location');
const [dateOpen, setDateOpen] = useState(false);
const [datestatus, setDatestatus] = useState('Today');
const [startdate, setStartdate] = useState(dayjs().format('YYYY-MM-DD'));
const [enddate, setEnddate] = useState(dayjs().format('YYYY-MM-DD'));
const handleChangetab = (e, i) => { const [searchword, setSearchword] = useState('');
setTabvalue(i); const [debouncedSearch, setDebouncedSearch] = useState('');
if (i === 0) {
setTabstatus('Created');
setCurrentStatus('created');
}
if (i === 1) {
setTabstatus('Pending');
setCurrentStatus('pending');
}
if (i === 2) {
setTabstatus('Delivered');
setCurrentStatus('delivered');
}
if (i === 3) {
setTabstatus('Cancelled');
setCurrentStatus('cancelled');
}
console.log(i);
};
const okclicked = () => {
setOpen(false);
};
const textFieldRef = useRef(null);
/* ============================================= || handleKeyPress (ctrl+k)| ============================================= */
useEffect(() => { useEffect(() => {
const handleKeyPress = (event) => { const handler = setTimeout(() => {
if (event.key === 'k' && (event.metaKey || event.ctrlKey)) { setDebouncedSearch(searchword);
event.preventDefault(); }, 400);
textFieldRef.current.focus(); return () => clearTimeout(handler);
} }, [searchword]);
if (event.key === 'Escape' && document.activeElement === textFieldRef.current) {
// Remove focus from the TextField
textFieldRef.current.blur();
}
};
document.addEventListener('keydown', handleKeyPress);
return () => { const statusMap = [
document.removeEventListener('keydown', handleKeyPress); {
label: 'Created',
value: 'created',
count: createdLenght,
icon: <AccessTimeIcon color="primary" fontSize="small" />
},
{
label: 'Pending',
value: 'pending',
count: pendingLenght,
icon: <LocalShippingOutlinedIcon color="primary" fontSize="small" />
},
{
label: 'Delivered',
value: 'delivered',
count: deliveredlenght,
icon: <CheckCircleOutline color="primary" fontSize="small" />
},
{
label: 'Cancelled',
value: 'cancelled',
count: cancelledLenght,
icon: <CancelOutlined color="primary" fontSize="small" />
}
];
const handleChangetab = (e, i) => {
setSearchword('');
setRowsPerPage(10);
setTabvalue(i);
setTabstatus(statusMap[i].label);
setCurrentStatus(statusMap[i].value);
setPage(0);
}; };
}, []);
const textFieldRef = useRef(null);
useHotkeyFocus(textFieldRef, 'k');
const handleChangePage = (event, newPage) => { const handleChangePage = (event, newPage) => {
setPage(newPage); setPage(newPage);
@@ -143,6 +147,7 @@ const Orders = () => {
}; };
const cancelorder = async () => { const cancelorder = async () => {
setLoading(true);
await axios await axios
.put(`${process.env.REACT_APP_URL}/orders/updateorder`, { .put(`${process.env.REACT_APP_URL}/orders/updateorder`, {
orderheaderid: orderheaderid, orderheaderid: orderheaderid,
@@ -157,39 +162,97 @@ const Orders = () => {
anchorOrigin: { vertical: 'top', horizontal: 'right' }, anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 2000 autoHideDuration: 2000
}); });
fetchtablecovered(); getOrders();
fetchorderscount(); fetchorderscount();
setCancelOpen(false); setCancelOpen(false);
} }
setLoading(false);
}) })
.catch((err) => { .catch((err) => {
console.log(err); console.log(err);
setLoading(false);
}); });
}; };
const fetchtablecovered = async () => { // const getOrders = async () => {
try { // try {
await axios // await axios
.get( // .get(
`${ // `${
process.env.REACT_APP_URL // process.env.REACT_APP_URL
}/orders/tenant/getorders/?tenantid=${tid}&locationid=${locationId}&status=${currentStatus}&fromdate=${startdate}&todate=${enddate}&pageno=${ // }/orders/tenant/getorders/?tenantid=${tid}&locationid=${locationId}&status=${currentStatus}&fromdate=${startdate}&todate=${enddate}&pageno=${
page + 1 // page + 1
}&pagesize=${rowsPerPage}&keyword=${searchword}` // }&pagesize=${rowsPerPage}&keyword=${debouncedSearch}`
) // )
.then((res) => { // .then((res) => {
setRows(res.data.details); // setRows(res.data.details);
}) // })
.catch((err) => { // .catch((err) => {
console.log(err); // console.log(err);
// });
// } catch (err) {
// console.log(err);
// }
// };
// useEffect(() => {
// getOrders();
// }, [tabstatus, startdate, enddate, page, rowsPerPage, debouncedSearch, locationId]);
const fetchOrders = async ({ pageParam = 1 }) => {
const res = await axios.get(
`${process.env.REACT_APP_URL}/orders/tenant/getorders/?tenantid=${tid}&locationid=${locationId}&status=${currentStatus}&fromdate=${startdate}&todate=${enddate}&pageno=${pageParam}&pagesize=${rowsPerPage}&keyword=${debouncedSearch}`
);
return {
data: res.data.details,
nextPage: res.data.details.length === rowsPerPage ? pageParam + 1 : undefined
};
};
const {
data: rowdata,
isError: isErrorGetOrders,
error: errorGetOrders,
fetchNextPage,
isLoading: isLoadingGeyOrders,
hasNextPage,
isFetchingNextPage
// status: rowdataStatus
} = useInfiniteQuery({
queryKey: [tabstatus, startdate, enddate, page, rowsPerPage, debouncedSearch, locationId],
queryFn: fetchOrders,
getNextPageParam: (lastPage) => lastPage.nextPage
}); });
} catch (err) {
console.log(err); const rows = rowdata ? rowdata.pages.flatMap((p) => p.data) : [];
useEffect(() => {
if (!hasNextPage) return;
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
fetchNextPage();
}
},
{
root: document.querySelector('.MuiTableContainer-root'), // 👈 or explicitly TableContainer
rootMargin: '0px',
threshold: 1.0
}
);
if (loadMoreRef.current) observer.observe(loadMoreRef.current);
return () => {
if (loadMoreRef.current) observer.unobserve(loadMoreRef.current);
};
}, [hasNextPage, fetchNextPage]);
const handleScroll = (event) => {
const { scrollTop, scrollHeight, clientHeight } = event.currentTarget;
if (scrollTop + clientHeight >= scrollHeight - 50) {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
} }
}; };
useEffect(() => {
fetchtablecovered();
}, [tabstatus, startdate, enddate, page, rowsPerPage, searchword, locationId]);
const fetchpercentage = async () => { const fetchpercentage = async () => {
setLoading(true); setLoading(true);
@@ -197,7 +260,7 @@ const Orders = () => {
await axios await axios
.get(`${process.env.REACT_APP_URL}/orders/getordersummary/?tenantid=${tid}`) .get(`${process.env.REACT_APP_URL}/orders/getordersummary/?tenantid=${tid}`)
.then((res) => { .then((res) => {
console.log(res); console.log('summary', res.data.details);
setCoveredorders(res.data.details.delivered.toString()); setCoveredorders(res.data.details.delivered.toString());
setCancelled(res.data.details.cancelled.toString()); setCancelled(res.data.details.cancelled.toString());
setUncoveredorders(res.data.details.pending.toString()); setUncoveredorders(res.data.details.pending.toString());
@@ -230,7 +293,6 @@ const Orders = () => {
) )
.then((res) => { .then((res) => {
console.log('fetchorderscount', res.data.details); console.log('fetchorderscount', res.data.details);
setCreatedLenght(res.data.details.created); setCreatedLenght(res.data.details.created);
setPendingLenght(res.data.details.pending); setPendingLenght(res.data.details.pending);
setDeliveredlenght(res.data.details.delivered); setDeliveredlenght(res.data.details.delivered);
@@ -252,7 +314,7 @@ const Orders = () => {
}; };
useEffect(() => { useEffect(() => {
fetchorderscount(); fetchorderscount();
}, [tabvalue, locationId]); }, [tabvalue, locationId, startdate, enddate]);
// ============================================= || gettenantlocations (branches) || ============================================= // ============================================= || gettenantlocations (branches) || =============================================
const gettenantlocations = async (id) => { const gettenantlocations = async (id) => {
try { try {
@@ -275,13 +337,20 @@ const Orders = () => {
return ( return (
<> <>
{loading && <Loader />} {loading && (
<Outlet /> <>
<Stack direction={{ xs: 'column', md: 'row' }} justifyContent="space-between" alignItems="center" spacing={2}> <Loader />
<CircularLoader />
</>
)}
{/* ============================================== || TitleCard || ============================================== */}
<Stack direction={{ xs: 'column', md: 'row' }} justifyContent="space-between" alignItems="center" sx={{ mt: -2, mb: 1 }}>
<Typography variant="h3">Orders</Typography> <Typography variant="h3">Orders</Typography>
</Stack> </Stack>
<Grid container spacing={3} sx={{ mt: 0.1 }}> {/* ============================================== || HoverSocialCard || ============================================== */}
<Grid item xs={12} sm={6} md={3}>
<Grid container spacing={3} sx={{}}>
<Grid item xs={12} custom500={6} md={3}>
<HoverSocialCard <HoverSocialCard
primary="Created Orders" primary="Created Orders"
secondary={created === '' ? <Skeleton sx={{ width: '30px' }} animation="wave" /> : created} secondary={created === '' ? <Skeleton sx={{ width: '30px' }} animation="wave" /> : created}
@@ -289,7 +358,7 @@ const Orders = () => {
color={theme.palette.primary.main} color={theme.palette.primary.main}
/> />
</Grid> </Grid>
<Grid item xs={12} sm={6} md={3}> <Grid item xs={12} custom500={6} md={3}>
<HoverSocialCard <HoverSocialCard
primary="Pending orders" primary="Pending orders"
secondary={uncoveredorders == '' ? <Skeleton sx={{ width: '30px' }} animation="wave" /> : uncoveredorders} secondary={uncoveredorders == '' ? <Skeleton sx={{ width: '30px' }} animation="wave" /> : uncoveredorders}
@@ -298,7 +367,7 @@ const Orders = () => {
/> />
</Grid> </Grid>
<Grid item xs={12} sm={6} md={3}> <Grid item xs={12} custom500={6} md={3}>
<HoverSocialCard <HoverSocialCard
primary="Delivered orders" primary="Delivered orders"
secondary={coveredorders === '' ? <Skeleton sx={{ width: '30px' }} animation="wave" /> : coveredorders} secondary={coveredorders === '' ? <Skeleton sx={{ width: '30px' }} animation="wave" /> : coveredorders}
@@ -307,7 +376,7 @@ const Orders = () => {
/> />
</Grid> </Grid>
<Grid item xs={12} sm={6} md={3}> <Grid item xs={12} custom500={6} md={3}>
<HoverSocialCard <HoverSocialCard
primary="Cancelled Orders" primary="Cancelled Orders"
secondary={cancelled === '' ? <Skeleton sx={{ width: '30px' }} animation="wave" /> : cancelled} secondary={cancelled === '' ? <Skeleton sx={{ width: '30px' }} animation="wave" /> : cancelled}
@@ -316,10 +385,20 @@ const Orders = () => {
/> />
</Grid> </Grid>
</Grid> </Grid>
<Stack direction={'row'} justifyContent={'space-between'} alignItems={'center'} sx={{ my: 2 }}> {/* ============================================== || Filters || ============================================== */}
<Stack
display={'flex'}
direction={'row'}
justifyContent={'space-between'}
alignItems={'center'}
flexWrap={'wrap'}
gap={2}
sx={{ my: 2 }}
>
{startdate && enddate && ( {startdate && enddate && (
<Stack direction="row" spacing={2}> <Stack direction="row" flexWrap={'wrap'} gap={2} alignItems="flex-start">
<Chip label={`Orders-${datestatus ? datestatus : ''}`} color="primary" variant="light" size="small" /> <Chip label={`Orders-${datestatus ? datestatus : ''}`} color="primary" variant="light" />
<Chip <Chip
label={ label={
@@ -327,23 +406,31 @@ const Orders = () => {
{dayjs(startdate).format('DD/MM/YYYY')} - {dayjs(enddate).format('DD/MM/YYYY')} {dayjs(startdate).format('DD/MM/YYYY')} - {dayjs(enddate).format('DD/MM/YYYY')}
</Typography> </Typography>
} }
sx={{ cursor: 'pointer' }}
variant="combined" variant="combined"
color="warning" color="warning"
size="small" onClick={() => setDateOpen(true)}
deleteIcon={<CalendarMonth style={{ fontSize: 18 }} />}
onDelete={() => setDateOpen(true)}
/> />
</Stack> </Stack>
)} )}
<Stack display={'flex'} flexDirection={'row'} alignItems={'center'} justifyContent={'space-between'} gap={2}> <Stack
<Stack direction={'row'} alignItems={'center'} justifyContent={'space-between'}> display={'flex'}
flexDirection={'row'}
alignItems={'center'}
flexWrap={'wrap'}
gap={2}
sx={{ width: { xs: '100%', custom800: 'auto' } }}
>
{tenantLocations.length == 1 ? ( {tenantLocations.length == 1 ? (
<TextField <TextField
// disabled={!isAppLocation || !isClient}
variant="outlined" variant="outlined"
fullWidth fullWidth
label={'Business Location'} label={'Business Location'}
value={tenantLocations[0].locationname} value={tenantLocations[0].locationname}
focused focused
sx={{ width: '350px' }} sx={{ width: 400 }}
InputProps={{ InputProps={{
style: { color: theme.palette.primary.main }, style: { color: theme.palette.primary.main },
startAdornment: ( startAdornment: (
@@ -356,12 +443,13 @@ const Orders = () => {
) : ( ) : (
<Autocomplete <Autocomplete
fullWidth fullWidth
// disabled={!isAppLocation || !isClient}
id="combo-box-demo" id="combo-box-demo"
options={tenantLocations || []} options={tenantLocations || []}
getOptionLabel={(option) => `${option.locationname} (${option.suburb})` || ''} getOptionLabel={(option) => `${option.locationname} (${option.suburb})` || ''}
renderInput={(params) => <TextField {...params} label={'Select Location'} value={locoName} color="primary" />} renderInput={(params) => <TextField {...params} label={'Select Location'} value={locoName} color="primary" />}
sx={{ width: '350px' }} sx={{
width: { xs: '100%', custom800: 400 }
}}
onChange={(event, value, reason) => { onChange={(event, value, reason) => {
if (value) { if (value) {
console.log('Business Locations', value); console.log('Business Locations', value);
@@ -375,62 +463,62 @@ const Orders = () => {
}} }}
/> />
)} )}
</Stack> {/* <Tooltip title="Date Filter">
<Tooltip title="Order Filter">
<IconButton <IconButton
color="secondary" color="secondary"
variant="light" variant="light"
sx={{ color: 'text.primary', bgcolor: 'grey.200' }} sx={{ color: 'text.primary', bgcolor: 'grey.200' }}
aria-haspopup="true" aria-haspopup="true"
onClick={() => setOpen(true)} onClick={() => setDateOpen(true)}
> >
<FilterList /> <FilterList />
</IconButton> </IconButton>
</Tooltip> </Tooltip> */}
</Stack> </Stack>
</Stack> </Stack>
<Grid item xs={12}> {/* ============================================== || Table || ============================================== */}
<Box sx={{ overflow: 'auto', border: 1, borderColor: 'grey.200', borderRadius: 2, backgroundColor: '#fff', minHeight: 350 }}>
<Stack <Stack
alignItems="center" display={'flex'}
justifyContent="space-between" flexDirection={'row'}
direction="row" justifyContent={'space-between'}
alignItems={'center'}
flexWrap={'wrap-reverse'}
gap={2}
sx={{ sx={{
p: 2, border: '1px solid ',
width: '100%' borderBottom: 0,
borderColor: 'bg.main',
p: 1.5
}} }}
> >
<Tabs value={tabvalue} onChange={handleChangetab} variant="scrollable" scrollButtons="auto"> {/* Tabs Wrapper */}
<Tab label="Created" icon={<Chip label={createdLenght} color="primary" variant="light" size="small" />} iconPosition="end" />
<Tab label="Pending" icon={<Chip label={pendingLenght} color="primary" variant="light" size="small" />} iconPosition="end" /> <Tabs value={tabvalue} onChange={handleChangetab} variant="scrollable" scrollButtons="auto" allowScrollButtonsMobile>
{statusMap.map((item, index) => (
<Tab <Tab
label="Delivered" key={index}
icon={<Chip label={deliveredlenght} color="primary" variant="light" size="small" />} label={
iconPosition="end" <Stack direction="row" alignItems="center" spacing={1}>
/> {item.icon}
<Tab <span>{item.label}</span>
label="Cancelled" <Chip label={item.count} color="primary" variant="light" size="small" />
icon={<Chip label={cancelledLenght} color="primary" variant="light" size="small" />} </Stack>
iconPosition="end" }
/> />
))}
</Tabs> </Tabs>
<Stack>
<FormControl sx={{ width: 250 }}> {/* Search Box */}
<Stack sx={{ width: { xs: '100%', custom1100: 350 } }}>
<FormControl fullWidth>
<OutlinedInput <OutlinedInput
inputRef={textFieldRef} inputRef={textFieldRef}
id="header-search"
aria-describedby="header-search-text"
inputProps={{
'aria-label': 'weight'
}}
placeholder="Search (ctrl+k)" placeholder="Search (ctrl+k)"
value={searchword} value={searchword}
onChange={(e) => { onChange={(e) => setSearchword(e.target.value)}
setSearchword(e.target.value);
}}
autoComplete="off" autoComplete="off"
startAdornment={ startAdornment={
<InputAdornment position="start" sx={{ mr: -0.5 }}> <InputAdornment position="start">
<SearchOutlined style={{ color: theme.palette.primary.main }} /> <SearchOutlined style={{ color: theme.palette.primary.main }} />
</InputAdornment> </InputAdornment>
} }
@@ -440,7 +528,7 @@ const Orders = () => {
sx={{ visibility: searchword ? 'visible' : 'hidden' }} sx={{ visibility: searchword ? 'visible' : 'hidden' }}
onClick={() => { onClick={() => {
setSearchword(''); setSearchword('');
fetchtablecovered(); getOrders();
fetchorderscount(); fetchorderscount();
}} }}
> >
@@ -452,20 +540,48 @@ const Orders = () => {
</FormControl> </FormControl>
</Stack> </Stack>
</Stack> </Stack>
<MainCard content={false}>
<Box sx={{ width: '100%', display: 'table', tableLayout: 'fixed' }}> <Fragment>
<Box sx={{ width: '100%' }}> <TableContainer
<TableContainer sx={{ width: '100%', borderBottom: 1, borderColor: 'divider' }}> onScroll={handleScroll}
<Table sx={{ minWidth: 750 }} aria-label="collapsible table" size={'medium'}> ref={containerRef}
sx={{
width: '100%',
borderBottom: 1,
borderColor: 'divider',
maxHeight: 'calc(100vh - 225px)',
overflow: 'auto',
'&::-webkit-scrollbar': {
width: '12px', // scroll bar width
cursor: 'pointer'
},
'&::-webkit-scrollbar-thumb': {
backgroundColor: theme.palette.primary.main, // thumb color
borderRadius: '8px',
cursor: 'pointer'
},
'&::-webkit-scrollbar-thumb:hover': {
backgroundColor: theme.palette.primary.dark, // hover color
cursor: 'pointer'
},
'&::-webkit-scrollbar-track': {
backgroundColor: theme.palette.primary.lighter,
cursor: 'pointer'
}
}}
>
<Table stickyHeader>
<TableHead> <TableHead>
<TableRow> <TableRow sx={{}}>
<TableCell> S.No</TableCell> <TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}> S.No</TableCell>
<TableCell> Orders</TableCell> <TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}> Orders</TableCell>
<TableCell> Pickup</TableCell> <TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}> Pickup</TableCell>
<TableCell>Drop </TableCell> <TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}> Drop </TableCell>
<TableCell> Notes</TableCell> <TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}> Notes</TableCell>
<TableCell>Status </TableCell> <TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}> Status </TableCell>
<TableCell>Action </TableCell> {currentStatus == 'created' && (
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>Action </TableCell>
)}
</TableRow> </TableRow>
</TableHead> </TableHead>
{loading && ( {loading && (
@@ -605,6 +721,7 @@ const Orders = () => {
</Stack> </Stack>
</TableCell> </TableCell>
{currentStatus == 'created' && (
<TableCell> <TableCell>
{row.orderstatus == 'created' && ( {row.orderstatus == 'created' && (
<> <>
@@ -627,26 +744,26 @@ const Orders = () => {
</> </>
)} )}
</TableCell> </TableCell>
)}
</TableRow> </TableRow>
</> </>
); );
})} })}
{rows?.length != 0 && (
<TableRow>
<TableCell colSpan={15} rowSpan={3}>
<div ref={loadMoreRef} style={{ height: 40, textAlign: 'center' }}>
{isFetchingNextPage ? <CircularProgress /> : hasNextPage ? <CircularProgress /> : 'No More Orders'}
</div>
</TableCell>
</TableRow>
)}
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
<TablePagination </Fragment>
rowsPerPageOptions={[5, 10, 25, 50, 100]} </MainCard>
component="div"
count={pageCount || 0}
rowsPerPage={rowsPerPage || 0}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</Box>
</Box>
</Box>
</Grid>
{/* ============================================== || cancel order || ============================================== */} {/* ============================================== || cancel order || ============================================== */}
<Dialog open={cancelOpen} onClose={() => setCancelOpen(false)} maxWidth="xs"> <Dialog open={cancelOpen} onClose={() => setCancelOpen(false)} maxWidth="xs">
<DialogContent sx={{ mt: 2, my: 1 }}> <DialogContent sx={{ mt: 2, my: 1 }}>
@@ -686,87 +803,15 @@ const Orders = () => {
</DialogContent> </DialogContent>
</Dialog> </Dialog>
{/* ============================================== || Date filter || ============================================== */} {/* ============================================== || Date filter || ============================================== */}
<Dialog open={open}> <DateFilterDialog
<DialogTitle align="left"> open={dateOpen}
<Typography variant="h4">Select Filter Options</Typography> onClose={() => setDateOpen(false)}
</DialogTitle> onApply={({ startDate, endDate, label }) => {
<DialogContent sx={{ width: '100%' }} className="datedialog"> setStartdate(startDate);
<DateRangePicker setEnddate(endDate);
open={open} setDatestatus(label);
toggle={() => setOpen(!open)}
id="daterange1"
onChange={(range) => {
if (range.label === 'All') {
setStartdate('');
setEnddate('');
setOpen(false);
} else {
setStartdate(dayjs(range.startDate).format('YYYY-MM-DD'));
setEnddate(dayjs(range.endDate).format('YYYY-MM-DD'));
if (range.label) {
setDatestatus(range.label);
} else {
setDatestatus('');
}
}
console.log(range);
}} }}
definedRanges={[
{
label: 'Today',
startDate: new Date(),
endDate: new Date()
},
{
label: 'Yesterday',
startDate: addDays(new Date(), -1),
endDate: addDays(new Date(), -1)
},
{
label: 'Tomorrow',
startDate: addDays(new Date(), +1),
endDate: addDays(new Date(), +1)
},
{
label: 'This Week',
startDate: startOfWeek(new Date()),
endDate: endOfWeek(new Date())
},
{
label: 'Last Week',
startDate: startOfWeek(addWeeks(new Date(), -1)),
endDate: endOfWeek(addWeeks(new Date(), -1))
},
{
label: 'Last 7 Days',
startDate: addWeeks(new Date(), -1),
endDate: new Date()
},
{
label: 'This Month',
startDate: startOfMonth(new Date()),
endDate: endOfMonth(new Date())
},
{
label: 'Last Month',
startDate: startOfMonth(addMonths(new Date(), -1)),
endDate: endOfMonth(addMonths(new Date(), -1))
}
// {
// label: 'All',
// startDate: new Date(),
// endDate: addDays(new Date(), -1),
// },
]}
/> />
</DialogContent>
<Stack direction="row" justifyContent="flex-end" sx={{ width: '100%', p: 2 }}>
<Button variant="contained" size="small" onClick={okclicked}>
ok
</Button>
</Stack>
</Dialog>
</> </>
); );
}; };

View File

@@ -0,0 +1,53 @@
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>
);
}

View File

@@ -740,7 +740,7 @@ const Createorder1 = () => {
setLoading(true); setLoading(true);
await axios await axios
.post(`${process.env.REACT_APP_URL}/orders/createorders`, arr) .post(`${process.env.REACT_APP_URL}/orders/create/grouporders`, arr)
.then((res) => { .then((res) => {
if (res.data.status) { if (res.data.status) {
enqueueSnackbar('Order Created Successfully', { enqueueSnackbar('Order Created Successfully', {
@@ -753,7 +753,7 @@ const Createorder1 = () => {
sendnotifications(); sendnotifications();
} }
navigate('/orders'); navigate('/nearle/orders');
} else { } else {
opentoast(res.data.message, 'warning'); opentoast(res.data.message, 'warning');
} }

View File

@@ -6,6 +6,8 @@ import { Empty } from 'antd';
import TaskAltIcon from '@mui/icons-material/TaskAlt'; import TaskAltIcon from '@mui/icons-material/TaskAlt';
import MyLocationIcon from '@mui/icons-material/MyLocation'; import MyLocationIcon from '@mui/icons-material/MyLocation';
import HighlightOffIcon from '@mui/icons-material/HighlightOff'; import HighlightOffIcon from '@mui/icons-material/HighlightOff';
import { enqueueSnackbar } from 'notistack';
import { CalendarMonth } from '@mui/icons-material';
// material-ui // material-ui
import { import {
@@ -60,7 +62,8 @@ import MainCard from 'components/MainCard';
import Loader from 'components/Loader'; import Loader from 'components/Loader';
import { useTheme } from '@mui/material/styles'; import { useTheme } from '@mui/material/styles';
import TitleCard from '../titleCard'; import TitleCard from '../titleCard';
import { getreportlocationsummary } from '../api/api'; import { getreportlocationsummary, gettenantlocations } from '../api/api';
import CircularLoader from 'components/nearle_components/CircularLoader';
function formatNumberToRupees(value) { function formatNumberToRupees(value) {
return new Intl.NumberFormat('en-IN', { return new Intl.NumberFormat('en-IN', {
@@ -70,6 +73,14 @@ function formatNumberToRupees(value) {
}).format(value); }).format(value);
} }
const opentoast = (message, variant, time) => {
enqueueSnackbar(message, {
variant: variant,
anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: time ? time : 1500
});
};
// ==============================|| MUI TABLE - ENHANCED ||============================== // // ==============================|| MUI TABLE - ENHANCED ||============================== //
export default function OrdersReport() { export default function OrdersReport() {
@@ -95,7 +106,6 @@ export default function OrdersReport() {
const [searchword, setSearchword] = useState(''); const [searchword, setSearchword] = useState('');
const textFieldRef = useRef(null); const textFieldRef = useRef(null);
const [ridersdata, setRidersdata] = useState(null); const [ridersdata, setRidersdata] = useState(null);
const [tenantLocations, setTenantlocations] = useState([]);
const [selectedLocation, setSelectedLocation] = useState(null); const [selectedLocation, setSelectedLocation] = useState(null);
const [locationId, setLocationId] = useState(0); const [locationId, setLocationId] = useState(0);
@@ -125,18 +135,16 @@ export default function OrdersReport() {
}, []); }, []);
// ============================================= || gettenantlocations (branches) || ============================================= // ============================================= || gettenantlocations (branches) || =============================================
const gettenantlocations = async () => {
try { const {
const res = await axios.get(`${process.env.REACT_APP_URL}/tenants/gettenantlocations?tenantid=${tenantid}`); data: tenantLocations,
console.log('gettenantlocations', res.data.details); isLoading: tenantLocationsIsLoading,
setTenantlocations(res.data.details); isError: tenantLocationsIsError,
} catch (err) { error: tenantLocationsError
console.log('gettenantlocations', err); } = useQuery({
} queryKey: ['tenantlocations'],
}; queryFn: gettenantlocations
useEffect(() => { });
gettenantlocations();
}, []);
// ==============================|| fetchOrdersSummary (orders summary)||============================== // // ==============================|| fetchOrdersSummary (orders summary)||============================== //
const { const {
@@ -196,17 +204,28 @@ export default function OrdersReport() {
calculate(); calculate();
}, [rows]); }, [rows]);
// if (isLoadingReports) return <Loader />; let errormessage = '';
if (isErrorReports) return 'An error has occurred:(isErrorReports) ' + reportsError.message;
if (isErrorReports && reportsError?.message) {
errormessage = `An error has occurred: (isErrorReports) ${reportsError.message}`;
} else if (tenantLocationsIsError && tenantLocationsError?.message) {
errormessage = `An error has occurred: (tenantLocationsIsError) ${tenantLocationsError.message}`;
}
useEffect(() => {
if (errormessage) {
console.log('errormessage', errormessage);
opentoast(errormessage, 'warning', 2000);
}
}, [errormessage]);
return ( return (
<> <>
{isLoadingReports && <Loader />} {(isLoadingReports || tenantLocationsIsLoading) && <Loader />}
<TitleCard title="Orders Summary" />{' '} {(isLoadingReports || tenantLocationsIsLoading) && <CircularLoader />}
<MainCard <TitleCard
content={false} title="Orders Summary"
title={ secondary={
<Stack display={'flex'} flexDirection={'row'} alignItems={'center'} justifyContent={'space-between'} flexWrap={'wrap'} gap={1}>
<Stack> <Stack>
{startdate && enddate && ( {startdate && enddate && (
<Stack direction="row" spacing={2} flexWrap={'wrap'} gap={1}> <Stack direction="row" spacing={2} flexWrap={'wrap'} gap={1}>
@@ -220,6 +239,12 @@ export default function OrdersReport() {
variant="combined" variant="combined"
color="warning" color="warning"
size="small" size="small"
deleteIcon={<CalendarMonth style={{ fontSize: 18 }} />}
onDelete={() => {
setOpen(true);
}}
onClick={() => setOpen(true)}
sx={{ cursor: 'pointer' }}
/> />
</Stack> </Stack>
)} )}
@@ -231,104 +256,101 @@ export default function OrdersReport() {
</> </>
)} )}
</Stack> </Stack>
}
/>{' '}
<MainCard
content={false}
title={
<Stack <Stack
direction="row"
gap={2}
flexWrap="wrap"
sx={{ sx={{
display: 'flex', alignItems: 'center',
flexDirection: 'row', width: '100%',
gap: 2, justifyContent: 'flex-end'
flexWrap: 'wrap',
flexGrow: 1,
justifyContent: 'right'
}} }}
> >
<FormControl sx={{ width: 250 }}> {/* Search Input */}
<FormControl sx={{ minWidth: 250, maxWidth: 400, flex: 1 }}>
<OutlinedInput <OutlinedInput
inputRef={textFieldRef} inputRef={textFieldRef}
aria-describedby="header-search-text"
inputProps={{
'aria-label': 'weight'
}}
sx={{ background: 'white' }}
size="large"
id="header-search" id="header-search"
placeholder="Search (ctrl+k)" placeholder="Search (Ctrl + K)"
value={searchword} value={searchword}
onChange={(e) => { onChange={(e) => setSearchword(e.target.value)}
setSearchword(e.target.value);
}}
autoComplete="off" autoComplete="off"
size="medium"
sx={{
bgcolor: 'white',
borderRadius: 2
}}
startAdornment={ startAdornment={
<InputAdornment position="start" sx={{ mr: -0.5 }}> <InputAdornment position="start">
<SearchOutlined /> <SearchOutlined />
</InputAdornment> </InputAdornment>
} }
endAdornment={ endAdornment={
<IconButton <InputAdornment position="end">
sx={{ visibility: searchword ? 'visible' : 'hidden' }} <IconButton sx={{ visibility: searchword ? 'visible' : 'hidden' }} onClick={() => setSearchword('')}>
onClick={() => { <ClearIcon sx={{ fontSize: 20, color: '#65387A' }} />
setSearchword('');
}}
>
<ClearIcon style={{ fontSize: 'medium', color: '#65387A' }} />
</IconButton> </IconButton>
</InputAdornment>
} }
/> />
</FormControl> </FormControl>
<Stack>
{tenantLocations.length == 1 ? ( {/* Location Input */}
{tenantLocations?.length === 1 ? (
<TextField <TextField
variant="outlined" variant="outlined"
label="Business Location"
value={tenantLocations[0]?.locationname}
fullWidth fullWidth
label={'Business Location'}
value={tenantLocations[0].locationname}
focused focused
sx={{ minWidth: 250 }} sx={{
minWidth: 250,
maxWidth: 400,
flex: 1,
borderRadius: 2
}}
InputProps={{ InputProps={{
style: { color: theme.palette.primary.main },
startAdornment: ( startAdornment: (
<InputAdornment position="start"> <InputAdornment position="start">
<MyLocationIcon color="primary" /> <MyLocationIcon color="primary" />
</InputAdornment> </InputAdornment>
) ),
sx: { bgcolor: 'white' }
}} }}
/> />
) : ( ) : (
<Autocomplete <Autocomplete
fullWidth fullWidth
id="combo-box-demo"
options={tenantLocations || []} options={tenantLocations || []}
value={selectedLocation} value={selectedLocation}
getOptionLabel={(option) => `${option.locationname} (${option.suburb})` || ''} getOptionLabel={(o) => `${o.locationname} (${o.suburb})`}
sx={{ minWidth: 250 }}
onChange={(event, value, reason) => { onChange={(event, value, reason) => {
setSelectedLocation(value); setSelectedLocation(value);
if (value) { setLocationId(value ? value.locationid : 0);
console.log('Business Locations', value); }}
setLocationId(value.locationid); sx={{
} minWidth: 250,
if (reason == 'clear') { maxWidth: 400,
setLocationId(0); flex: 1
} }}
renderInput={(params) => (
<TextField
{...params}
label="Choose Location"
color="primary"
sx={{
bgcolor: 'white',
borderRadius: 2
}} }}
renderInput={(params) => <TextField {...params} label="Choose Location" color="primary" />}
/> />
)} )}
</Stack> />
)}
<Tooltip title="Order Filter">
<IconButton
color="secondary"
variant="light"
sx={{
color: 'text.primary',
bgcolor: 'grey.200'
}}
onClick={() => setOpen(true)}
>
<FilterList />
</IconButton>
</Tooltip>
</Stack>
</Stack> </Stack>
} }
> >
@@ -336,8 +358,9 @@ export default function OrdersReport() {
sx={{ sx={{
overflow: 'auto', overflow: 'auto',
'&::-webkit-scrollbar': { '&::-webkit-scrollbar': {
width: '3px', width: '12px', // Width of vertical scrollbar
height: '3px' height: '14px', // Height of horizontal scrollbar,
borderRadius: 10
}, },
'&::-webkit-scrollbar-thumb': { '&::-webkit-scrollbar-thumb': {
backgroundColor: '#65387A' // Color of the scrollbar thumb backgroundColor: '#65387A' // Color of the scrollbar thumb
@@ -357,7 +380,7 @@ export default function OrdersReport() {
Deliveries{' '} Deliveries{' '}
</TableCell> </TableCell>
<TableCell rowSpan={2}> Kilometer</TableCell> <TableCell rowSpan={2}> Kilometer</TableCell>
<TableCell rowSpan={2}>Charges </TableCell> {/* <TableCell rowSpan={2}>Charges </TableCell> */}
<TableCell rowSpan={2}>Amount </TableCell> <TableCell rowSpan={2}>Amount </TableCell>
<TableCell rowSpan={2}> Action</TableCell> <TableCell rowSpan={2}> Action</TableCell>
</TableRow> </TableRow>
@@ -380,10 +403,6 @@ export default function OrdersReport() {
<TableRow <TableRow
key={row.locationid} key={row.locationid}
sx={{ sx={{
bgcolor: openRow === row.locationid ? '#e1bee7' : null,
'&:hover': {
bgcolor: openRow === row.locationid ? '#e1bee7!important' : null
},
cursor: openRow === row.locationid ? 'pointer' : null cursor: openRow === row.locationid ? 'pointer' : null
}} }}
> >
@@ -418,7 +437,7 @@ export default function OrdersReport() {
/> />
</Tooltip> </Tooltip>
<br /> {/* <br />
<Tooltip title="Actual kms" placement="bottom"> <Tooltip title="Actual kms" placement="bottom">
<Chip <Chip
size="small" size="small"
@@ -431,10 +450,10 @@ export default function OrdersReport() {
minWidth: 80 minWidth: 80
}} }}
/> />
</Tooltip> </Tooltip> */}
</TableCell> </TableCell>
<TableCell align="left"> {/* <TableCell align="left"> */}
<Tooltip title="Pay on Delivery" placement="top"> {/* <Tooltip title="Pay on Delivery" placement="top">
<Chip <Chip
size="small" size="small"
label={formatNumberToRupees(row.payondelivery)} label={formatNumberToRupees(row.payondelivery)}
@@ -450,8 +469,8 @@ export default function OrdersReport() {
}} }}
/> />
</Tooltip> </Tooltip>
<br /> <br /> */}
<Tooltip title="Pay Later" placement="bottom"> {/* <Tooltip title="Pay Later" placement="bottom">
<Chip <Chip
size="small" size="small"
label={formatNumberToRupees(row.paylater)} label={formatNumberToRupees(row.paylater)}
@@ -465,8 +484,8 @@ export default function OrdersReport() {
minWidth: 80 minWidth: 80
}} }}
/> />
</Tooltip> </Tooltip> */}
</TableCell> {/* </TableCell> */}
<TableCell align="right"> <TableCell align="right">
<Tooltip title="Total Charges" placement="top"> <Tooltip title="Total Charges" placement="top">
<Chip <Chip
@@ -506,9 +525,9 @@ export default function OrdersReport() {
{openRow === row.locationid && ( {openRow === row.locationid && (
<TableRow <TableRow
sx={{ sx={{
bgcolor: openRow === row.locationid ? '#f3e5f5' : null, bgcolor: 'white',
'&:hover': { '&:hover': {
bgcolor: openRow === row.locationid ? '#f3e5f5!important' : null bgcolor: 'white!important'
}, },
cursor: openRow === row.locationid ? 'pointer' : null cursor: openRow === row.locationid ? 'pointer' : null
}} }}
@@ -516,35 +535,56 @@ export default function OrdersReport() {
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={15}> <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={15}>
<Collapse in={openRow === row.locationid} timeout="auto" unmountOnExit> <Collapse in={openRow === row.locationid} timeout="auto" unmountOnExit>
<Box sx={{ margin: 1 }}> <Box sx={{ margin: 1 }}>
<Typography variant="h5" gutterBottom component="div">
Riders Summary
</Typography>
<Table size="small" aria-label="purchases"> <Table size="small" aria-label="purchases">
<TableHead <TableHead
sx={{ sx={{
bgcolor: '#f3e5f5', bgcolor: 'white',
'&:onhover': { '&:onhover': {
bgcolor: '#f3e5f5!important' bgcolor: 'white !important'
} }
}} }}
> >
<TableRow> <TableRow
<TableCell>#</TableCell> sx={{
bgcolor: openRow === row.locationid ? theme.palette.secondary.lighter : null
}}
>
<TableCell align="center">#</TableCell>
<TableCell>Rider</TableCell> <TableCell>Rider</TableCell>
<TableCell align="left">Deliveries</TableCell> <TableCell align="center">Deliveries</TableCell>
<TableCell align="left">Assigned</TableCell> <TableCell align="center">Pending</TableCell>
<TableCell align="left">Accepted</TableCell> <TableCell align="center">Assigned</TableCell>
<TableCell align="left">Picked</TableCell> <TableCell align="center">Accepted</TableCell>
<TableCell align="left">Delivered</TableCell> <TableCell align="center">Arrived</TableCell>
<TableCell align="center">kms/Actualkms</TableCell> <TableCell align="center">Picked</TableCell>
<TableCell align="center">POD/PLA</TableCell> <TableCell align="center">Skipped</TableCell>
<TableCell align="center">Delivered</TableCell>
<TableCell align="center">kms</TableCell>
{/* <TableCell align="center">POD/PLA</TableCell> */}
<TableCell align="center">Charges</TableCell> <TableCell align="center">Charges</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody
sx={{
bgcolor: 'white',
'&:onhover': {
bgcolor: 'white !important'
}
}}
>
{ridersdata?.map((rider, index) => ( {ridersdata?.map((rider, index) => (
<TableRow key={rider?.tenantname}> <TableRow
<TableCell padding="none">{index + 1}</TableCell> key={rider?.tenantname}
// sx={{
// bgcolor: openRow === row.locationid ? '#f3e5f5' : null,
// '&:hover': {
// bgcolor: openRow === row.locationid ? '#f3e5f5!important' : null
// }
// }}
>
<TableCell align="center" padding="none">
{index + 1}
</TableCell>
<TableCell align="left"> <TableCell align="left">
<Stack direction="row" sx={{ ml: -2 }}> <Stack direction="row" sx={{ ml: -2 }}>
{rider?.firstname} {rider?.firstname}
@@ -555,13 +595,16 @@ export default function OrdersReport() {
)} )}
</Stack> </Stack>
</TableCell> </TableCell>
<TableCell align="left">{rider?.deliveries}</TableCell> <TableCell align="center">{rider?.totalorders}</TableCell>
<TableCell align="left">{rider?.Assigened}</TableCell> <TableCell align="center">{rider?.pending}</TableCell>
<TableCell align="left">{rider?.Accepted}</TableCell> <TableCell align="center">{rider?.assigned}</TableCell>
<TableCell align="left">{rider?.Picked}</TableCell> <TableCell align="center">{rider?.accepted}</TableCell>
<TableCell align="left">{rider?.delivered}</TableCell> <TableCell align="center">{rider?.picked}</TableCell>
<TableCell align="center">{rider?.arrived}</TableCell>
<TableCell align="center">{rider?.skipped}</TableCell>
<TableCell align="center">{rider?.delivered}</TableCell>
<TableCell align="center"> <TableCell align="center">
<Tooltip title="kms" placement="top"> {/* <Tooltip title="kms" placement="top"> */}
<Chip <Chip
size="small" size="small"
label={rider?.kms} label={rider?.kms}
@@ -574,8 +617,8 @@ export default function OrdersReport() {
minWidth: 80 minWidth: 80
}} }}
/> />
</Tooltip> {/* </Tooltip> */}
<Tooltip title="Actual kms" placement="top"> {/* <Tooltip title="Actual kms" placement="top">
<Chip <Chip
size="small" size="small"
label={rider?.actualkms} label={rider?.actualkms}
@@ -587,11 +630,11 @@ export default function OrdersReport() {
minWidth: 80 minWidth: 80
}} }}
/> />
</Tooltip> </Tooltip> */}
</TableCell> </TableCell>
<TableCell align="center"> {/* <TableCell align="center"> */}
<Tooltip title="Pay on Delivery" placement="top"> {/* <Tooltip title="Pay on Delivery" placement="top">
<Chip <Chip
size="small" size="small"
label={formatNumberToRupees(rider?.payondelivery)} label={formatNumberToRupees(rider?.payondelivery)}
@@ -604,9 +647,9 @@ export default function OrdersReport() {
minWidth: 80 minWidth: 80
}} }}
/> />
</Tooltip> </Tooltip> */}
<Tooltip title="Paylater" placement="top"> {/* <Tooltip title="Paylater" placement="top"> */}
<Chip {/* <Chip
size="small" size="small"
label={formatNumberToRupees(rider?.Paylater)} label={formatNumberToRupees(rider?.Paylater)}
sx={{ sx={{
@@ -616,14 +659,14 @@ export default function OrdersReport() {
cursor: 'pointer', cursor: 'pointer',
minWidth: 80 minWidth: 80
}} }}
/> /> */}
</Tooltip> {/* </Tooltip> */}
</TableCell> {/* </TableCell> */}
<TableCell align="center"> <TableCell align="center">
<Tooltip title="Amount" placement="top"> <Tooltip title="Amount" placement="top">
<Chip <Chip
size="small" size="small"
label={formatNumberToRupees(rider?.Deliveryamt)} label={formatNumberToRupees(rider?.deliveryamt)}
sx={{ sx={{
color: 'primary.main', color: 'primary.main',
bgcolor: '#e1bee7', bgcolor: '#e1bee7',

View File

@@ -53,13 +53,14 @@ import {
startOfWeek startOfWeek
// startOfYear, // startOfYear,
} from 'date-fns'; } from 'date-fns';
import { FilterList } from '@mui/icons-material'; import { CalendarMonth, FilterList } from '@mui/icons-material';
// project imports // project imports
import { fetchDeliverySummary, fetchorderdetails } from '../api/api'; import { fetchDeliverySummary, fetchorderdetails } from '../api/api';
import MainCard from 'components/MainCard'; import MainCard from 'components/MainCard';
import { CSVExport } from 'components/third-party/ReactTable'; import { CSVExport } from 'components/third-party/ReactTable';
import Loader from 'components/Loader'; import Loader from 'components/Loader';
import { useDebounce } from 'components/nearle_components/useDebounce';
function formatNumberToRupees(value) { function formatNumberToRupees(value) {
return new Intl.NumberFormat('en-IN', { return new Intl.NumberFormat('en-IN', {
@@ -95,6 +96,7 @@ export default function OrdersDetails() {
const [locationId, setLocationId] = useState(0); const [locationId, setLocationId] = useState(0);
const [locoName, setLocoName] = useState('Select Location'); const [locoName, setLocoName] = useState('Select Location');
const debouncedSearch = useDebounce(searchword, 500);
const status = [ const status = [
{ id: 0, status: 'All', statusLow: 'All' }, { id: 0, status: 'All', statusLow: 'All' },
{ id: 1, status: 'Pending', statusLow: 'pending' }, { id: 1, status: 'Pending', statusLow: 'pending' },
@@ -186,15 +188,15 @@ export default function OrdersDetails() {
isFetchingNextPage isFetchingNextPage
// status: rowdataStatus // status: rowdataStatus
} = useInfiniteQuery({ } = useInfiniteQuery({
queryKey: [startdate, enddate, currentStatus, locationId], queryKey: [startdate, enddate, currentStatus, locationId, debouncedSearch],
queryFn: fetchorderdetails, queryFn: fetchorderdetails,
getNextPageParam: (lastPage) => lastPage.nextPage getNextPageParam: (lastPage) => lastPage.nextPage
}); });
const rows = rowdata?.pages.flatMap((page) => page.details) || []; const rows = rowdata?.pages.flatMap((page) => page.details) || [];
useEffect(() => { useEffect(() => {
if (!hasNextPage) return; if (!hasNextPage) return;
const observer = new IntersectionObserver( const observer = new IntersectionObserver(
(entries) => { (entries) => {
if (entries[0].isIntersecting) { if (entries[0].isIntersecting) {
@@ -207,9 +209,7 @@ export default function OrdersDetails() {
threshold: 1.0 threshold: 1.0
} }
); );
if (loadMoreRef.current) observer.observe(loadMoreRef.current); if (loadMoreRef.current) observer.observe(loadMoreRef.current);
return () => { return () => {
if (loadMoreRef.current) observer.unobserve(loadMoreRef.current); if (loadMoreRef.current) observer.unobserve(loadMoreRef.current);
}; };
@@ -245,6 +245,7 @@ export default function OrdersDetails() {
}, [currentStatus, deliverycount]); }, [currentStatus, deliverycount]);
// ==============================|| calculate||============================== // // ==============================|| calculate||============================== //
const calculate = () => { const calculate = () => {
let calculatedTotalCharge = 0; let calculatedTotalCharge = 0;
let calculatedTotalAmount = 0; let calculatedTotalAmount = 0;
@@ -268,23 +269,9 @@ export default function OrdersDetails() {
if (isErrorOrderDetails) return 'An error has occurred:(isErrorOrderDetails) ' + orderDetailsError.message; if (isErrorOrderDetails) return 'An error has occurred:(isErrorOrderDetails) ' + orderDetailsError.message;
const filteredOrders = rows.filter((row) =>
row.orderstatus == ''
? row.orderstatus.toLowerCase().includes(searchword.toLowerCase())
: row.orderstatus.toLowerCase().includes(searchword.toLowerCase()) ||
row.ordernotes.toLowerCase().includes(searchword.toLowerCase()) ||
row.tenantname.toLowerCase().includes(searchword.toLowerCase()) ||
row.orderid.toLowerCase().includes(searchword.toLowerCase()) ||
row.pickupcustomer.toLowerCase().includes(searchword.toLowerCase()) ||
row.pickupcontactno.toLowerCase().includes(searchword.toLowerCase()) ||
row.pickuplocation.toLowerCase().includes(searchword.toLowerCase()) ||
row.deliverycustomer.toLowerCase().includes(searchword.toLowerCase()) ||
row.deliverycontactno.toLowerCase().includes(searchword.toLowerCase()) ||
row.deliverylocation.toLowerCase().includes(searchword.toLowerCase()) ||
row.ridername.toLowerCase().includes(searchword.toLowerCase())
);
// to download ex format filtered data // to download ex format filtered data
const csvData = filteredOrders.map((order) => ({
const csvData = rows.map((order) => ({
tenantname: order.tenantname, tenantname: order.tenantname,
tenantcity: order.tenantcity, tenantcity: order.tenantcity,
tenantcontactno: order.tenantcontactno, tenantcontactno: order.tenantcontactno,
@@ -345,13 +332,10 @@ export default function OrdersDetails() {
return ( return (
<> <>
{isLoadingOrderDetails && <Loader />} {isLoadingOrderDetails && <Loader />}
<TitleCard title="Orders Details" /> <TitleCard
title="Orders Details"
<MainCard secondary={
content={false} <Stack display={'flex'} flexDirection={'row'} alignItems={'center'} gap={2}>
title={
<Stack display={'flex'} flexDirection={'row'} alignItems={'center'} justifyContent={'space-between'} flexWrap="wrap">
<Stack alignItems="flex-start" spacing={1}>
{startdate && enddate && ( {startdate && enddate && (
<Stack direction="row" spacing={2}> <Stack direction="row" spacing={2}>
<Badge <Badge
@@ -375,6 +359,12 @@ export default function OrdersDetails() {
variant="combined" variant="combined"
color="warning" color="warning"
size="small" size="small"
deleteIcon={<CalendarMonth style={{ fontSize: 18 }} />}
onDelete={() => {
setOpen(true);
}}
onClick={() => setOpen(true)}
sx={{ cursor: 'pointer' }}
/> />
</Stack> </Stack>
)} )}
@@ -386,9 +376,14 @@ export default function OrdersDetails() {
</Stack> </Stack>
</div> </div>
)} )}
<CSVExport data={csvData} filename={`Orders_Detail_${dayjs().format('YYYY-MM-DD_HHmmss')}.csv`} />
</Stack> </Stack>
<Stack sx={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 2 }}> }
<Stack direction={'row'} alignItems={'center'} justifyContent={'space-between'}> />
<MainCard
content={false}
title={
<Stack sx={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 2, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
{tenantLocations.length == 1 ? ( {tenantLocations.length == 1 ? (
<TextField <TextField
// disabled={!isAppLocation || !isClient} // disabled={!isAppLocation || !isClient}
@@ -397,7 +392,7 @@ export default function OrdersDetails() {
label={'Business Location'} label={'Business Location'}
value={tenantLocations[0].locationname} value={tenantLocations[0].locationname}
focused focused
sx={{ width: '350px' }} sx={{ minWidth: 250, maxWidth: 400, flex: 1 }}
InputProps={{ InputProps={{
style: { color: theme.palette.primary.main }, style: { color: theme.palette.primary.main },
startAdornment: ( startAdornment: (
@@ -415,7 +410,7 @@ export default function OrdersDetails() {
options={tenantLocations || []} options={tenantLocations || []}
getOptionLabel={(option) => `${option.locationname} (${option.suburb})` || ''} getOptionLabel={(option) => `${option.locationname} (${option.suburb})` || ''}
renderInput={(params) => <TextField {...params} label={locoName} color="primary" />} renderInput={(params) => <TextField {...params} label={locoName} color="primary" />}
sx={{ width: '300px' }} sx={{ minWidth: 250, maxWidth: 400, flex: 1 }}
onChange={(event, value, reason) => { onChange={(event, value, reason) => {
if (value) { if (value) {
console.log('Business Locations', value); console.log('Business Locations', value);
@@ -429,9 +424,9 @@ export default function OrdersDetails() {
}} }}
/> />
)} )}
</Stack>
<Autocomplete <Autocomplete
sx={{ minWidth: 200 }} sx={{ minWidth: 250, maxWidth: 400, flex: 1 }}
disablePortal disablePortal
id="combo-box-demo" id="combo-box-demo"
options={status} options={status}
@@ -446,7 +441,7 @@ export default function OrdersDetails() {
}} }}
renderInput={(params) => <TextField {...params} label={'Select Status'} />} renderInput={(params) => <TextField {...params} label={'Select Status'} />}
/> />
<FormControl sx={{ width: 250 }}> <FormControl sx={{ minWidth: 250, maxWidth: 400, flex: 1 }}>
<OutlinedInput <OutlinedInput
inputRef={textFieldRef} inputRef={textFieldRef}
aria-describedby="header-search-text" aria-describedby="header-search-text"
@@ -482,7 +477,7 @@ export default function OrdersDetails() {
/> />
</FormControl> </FormControl>
<Tooltip title="Order Filter"> {/* <Tooltip title="Order Filter">
<IconButton <IconButton
color="secondary" color="secondary"
variant="light" variant="light"
@@ -496,10 +491,7 @@ export default function OrdersDetails() {
> >
<FilterList /> <FilterList />
</IconButton> </IconButton>
</Tooltip> </Tooltip> */}
<CSVExport data={csvData} filename={`Orders_Detail_${dayjs().format('YYYY-MM-DD_HHmmss')}.csv`} />
</Stack>
</Stack> </Stack>
} }
> >
@@ -531,24 +523,24 @@ export default function OrdersDetails() {
> >
<TableRow> <TableRow>
<TableCell sx={{ position: 'sticky !important' }}># </TableCell> <TableCell sx={{ position: 'sticky !important' }}># </TableCell>
<TableCell sx={{ position: 'sticky !important' }}>Map</TableCell> {/* <TableCell sx={{ position: 'sticky !important' }}> {<SlLocationPin style={{ fontWeight: 1000 }} />}</TableCell> */}
<TableCell sx={{ whiteSpace: 'nowrap', position: 'sticky !important' }}>Tenant Name </TableCell> <TableCell sx={{ whiteSpace: 'nowrap', position: 'sticky !important' }}>Location </TableCell>
<TableCell sx={{ position: 'sticky !important' }}>Pickup </TableCell> <TableCell sx={{ position: 'sticky !important' }}>Pickup </TableCell>
<TableCell sx={{ position: 'sticky !important' }}> Drop </TableCell> <TableCell sx={{ position: 'sticky !important' }}> Drop </TableCell>
<TableCell sx={{ position: 'sticky !important' }}> Status </TableCell> <TableCell sx={{ position: 'sticky !important' }}> Status </TableCell>
<TableCell sx={{ position: 'sticky !important' }}> Assignes </TableCell> <TableCell sx={{ position: 'sticky !important' }}> Assigned </TableCell>
<TableCell sx={{ position: 'sticky !important' }}> Accepted </TableCell> <TableCell sx={{ position: 'sticky !important' }}> Accepted </TableCell>
<TableCell sx={{ position: 'sticky !important' }}> Arrived </TableCell> <TableCell sx={{ position: 'sticky !important' }}> Arrived </TableCell>
<TableCell sx={{ position: 'sticky !important' }}> Picked </TableCell> <TableCell sx={{ position: 'sticky !important' }}> Picked </TableCell>
<TableCell sx={{ position: 'sticky !important' }}> Delivered</TableCell> <TableCell sx={{ position: 'sticky !important' }}> Delivered</TableCell>
<TableCell sx={{ position: 'sticky !important' }}> Cancelled </TableCell> <TableCell sx={{ position: 'sticky !important' }}> Cancelled </TableCell>
<TableCell sx={{ position: 'sticky !important' }}> Notes </TableCell> {/* <TableCell sx={{ position: 'sticky !important' }}> Notes </TableCell> */}
<TableCell sx={{ position: 'sticky !important' }}> Kms </TableCell> <TableCell sx={{ position: 'sticky !important' }}> Kms </TableCell>
<TableCell sx={{ position: 'sticky !important' }}> Charges </TableCell> <TableCell sx={{ position: 'sticky !important' }}> Charges </TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{filteredOrders.length == 0 && ( {rows?.length == 0 && (
<> <>
<TableCell colSpan={15}> <TableCell colSpan={15}>
<Stack width={'100%'} direction={'row'} justifyContent={'center'}> <Stack width={'100%'} direction={'row'} justifyContent={'center'}>
@@ -557,12 +549,12 @@ export default function OrdersDetails() {
</TableCell> </TableCell>
</> </>
)} )}
{filteredOrders.map((row, index) => { {rows?.map((row, index) => {
return ( return (
filteredOrders.length !== 0 && ( rows?.length !== 0 && (
<TableRow> <TableRow>
<TableCell sx={{ width: '10px' }}>{index + 1}</TableCell> <TableCell sx={{ width: '10px' }}>{index + 1}</TableCell>
<TableCell {/* <TableCell
sx={{ width: '10px', cursor: 'pointer' }} sx={{ width: '10px', cursor: 'pointer' }}
onClick={() => { onClick={() => {
console.log('row', row); console.log('row', row);
@@ -572,13 +564,14 @@ export default function OrdersDetails() {
}} }}
> >
{<SlLocationPin />} {<SlLocationPin />}
</TableCell> </TableCell> */}
<TableCell <TableCell
sx={{ sx={{
textAlign: 'start' textAlign: 'start',
whiteSpace: 'nowrap'
}} }}
> >
{row.tenantname} {row.locationname}
<Typography variant="body2" noWrap> <Typography variant="body2" noWrap>
{row.orderid} {row.orderid}
</Typography> </Typography>
@@ -591,7 +584,7 @@ export default function OrdersDetails() {
</TableCell> </TableCell>
<TableCell align="left"> <TableCell align="left">
<Stack direction={'row'} spacing={1}> <Stack direction={'row'} spacing={1}>
<Stack direction="column"> <Stack direction="column" sx={{ whiteSpace: 'nowrap' }}>
<Typography variant="caption">{row.pickupcustomer}</Typography> <Typography variant="caption">{row.pickupcustomer}</Typography>
<Typography variant="caption" color="textSecondary"> <Typography variant="caption" color="textSecondary">
{row.pickupcontactno} {row.pickupcontactno}
@@ -606,7 +599,7 @@ export default function OrdersDetails() {
</TableCell> </TableCell>
<TableCell align="left"> <TableCell align="left">
<Stack direction={'row'} spacing={1}> <Stack direction={'row'} spacing={1}>
<Stack direction="column"> <Stack direction="column" sx={{ whiteSpace: 'nowrap' }}>
<Typography variant="caption">{row.deliverycustomer}</Typography> <Typography variant="caption">{row.deliverycustomer}</Typography>
<Typography variant="caption" color="textSecondary"> <Typography variant="caption" color="textSecondary">
{row.deliverycontactno} {row.deliverycontactno}
@@ -695,13 +688,12 @@ export default function OrdersDetails() {
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell align="left"> {/* <TableCell align="left">
<Typography variant="caption">{row.ordernotes}</Typography> <Typography variant="caption">{row.ordernotes}</Typography>
</TableCell> </TableCell> */}
<TableCell align="left"> <TableCell align="left">
<Stack direction={'column'} spacing={1}> <Stack direction={'column'} spacing={1}>
<Tooltip title=" KMS" placement="top">
<Chip <Chip
label={ label={
row.orderstatus === 'cancelled' || row.orderstatus === 'cancelled' || row.kms == '' row.orderstatus === 'cancelled' || row.orderstatus === 'cancelled' || row.kms == ''
@@ -709,11 +701,11 @@ export default function OrdersDetails() {
: parseInt(row.kms).toFixed(1) : parseInt(row.kms).toFixed(1)
} }
size="small" size="small"
variant="light" variant="contained"
color="error" color="warning"
/> />
</Tooltip>
<Tooltip title="Actual KMS"> {/* <Tooltip title="Actual KMS">
<Chip <Chip
label={ label={
row.deliverystatus === 'cancelled' || row.actualkms === '' || row.actualkms === 'null' row.deliverystatus === 'cancelled' || row.actualkms === '' || row.actualkms === 'null'
@@ -725,42 +717,44 @@ export default function OrdersDetails() {
color="success" color="success"
variant="light" variant="light"
/> />
</Tooltip> </Tooltip> */}
</Stack> </Stack>
</TableCell> </TableCell>
<TableCell align="right"> <TableCell align="right">
<Stack direction={'column'} spacing={1}> <Stack direction={'column'} spacing={1}>
<Tooltip title=" Delivery Charge" placement="top">
<Chip <Chip
label={ label={
row.orderstatus === 'cancelled' || row.deliverycharges == '' ? `${0}.00` : `${row.deliverycharges}.00` row.orderstatus === 'cancelled' || row.deliverycharges == '' ? `${0}.00` : `${row.deliverycharges}.00`
} }
size="small" size="small"
variant="light" variant="contained"
color="error" color="primary"
/> />
</Tooltip>
<Tooltip title="Delivery Amount"> {/* <Tooltip title="Delivery Amount">
<Chip <Chip
label={row.deliveryamt == '' ? `₹ ${0}.00` : `₹ ${row.deliveryamt}.00`} label={row.deliveryamt == '' ? `₹ ${0}.00` : `₹ ${row.deliveryamt}.00`}
size="small" size="small"
color="success" color="success"
variant="light" variant="light"
/> />
</Tooltip> </Tooltip> */}
</Stack> </Stack>
</TableCell> </TableCell>
</TableRow> </TableRow>
) )
); );
})} })}
{rows?.length != 0 && (
<TableRow> <TableRow>
<TableCell colSpan={15} rowSpan={3}> <TableCell colSpan={15} rowSpan={3}>
<div ref={loadMoreRef} style={{ height: 40, textAlign: 'center' }}> <div ref={loadMoreRef} style={{ height: 40, textAlign: 'center' }}>
{isFetchingNextPage ? <CircularProgress /> : hasNextPage ? <CircularProgress /> : 'No more results'} {isFetchingNextPage ? <CircularProgress /> : hasNextPage ? <CircularProgress /> : 'No More Orders'}
</div> </div>
</TableCell> </TableCell>
</TableRow> </TableRow>
)}
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>

View File

@@ -1,7 +1,209 @@
import React from 'react'; import * as React from 'react';
import { useState } from 'react';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import { useQuery } from '@tanstack/react-query';
// material-ui
import {
Divider,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
FormControl,
OutlinedInput,
InputAdornment,
Chip,
Stack
} from '@mui/material';
const riderLogs = () => { import dayjs from 'dayjs';
return <div>riderLogs</div>; var utc = require('dayjs/plugin/utc');
}; dayjs.extend(utc);
import { SearchOutlined, CloseOutlined } from '@ant-design/icons';
import Loader from 'components/Loader';
// project imports
import MainCard from 'components/MainCard';
import { Empty } from 'antd';
import TitleCard from '../titleCard';
import { fetchAppLocations, fetchRidersLogs } from '../api/api';
export default riderLogs; function formatDate(dateString) {
const date = dayjs(dateString);
const formattedDate = date.format('DD-MM-YYYY ');
return formattedDate;
}
const formatTime = (timeString) =>
new Date('2024-01-01T' + timeString + 'Z').toLocaleTimeString('en-US', {
timeZone: 'UTC',
hour12: true,
hour: '2-digit',
minute: '2-digit'
});
// ==============================|| RidersLogs ||============================== //
export default function RidersLogs() {
const tenantid = localStorage.getItem('tenantid');
const [rowsPerPage, setRowsPerPage] = useState(10);
const [startdate, setStartdate] = useState(dayjs().format('YYYY-MM-DD'));
const [searchword, setSearchword] = useState('');
const [showClose, SetShowClose] = useState(false);
/* ============================================= || fetchRidersLogs| ============================================= */
const {
data: rows = [], // Default to empty array
isLoading: IsRiderLogsLoading,
isError: IsRiderLogsError,
error: RiderLogsError
} = useQuery({
queryKey: [tenantid, startdate], // Meaningful query key
queryFn: fetchRidersLogs,
enabled: !!tenantid && !!startdate, // Fetch only if appId & startdate exist
refetchInterval: 300000 // Auto-fetch every 5 minutes
});
React.useEffect(() => {
setRowsPerPage(rows?.length + 1);
}, [rows]);
{
IsRiderLogsError && console.log('RiderLogsError', RiderLogsError);
}
return (
<>
{IsRiderLogsLoading && <Loader />}
<TitleCard title="Riders Logs" />
<MainCard
content={false}
title={
<Stack display={'flex'} flexDirection={'row'} alignItems={'center'} justifyContent={'space-between'} flexWrap={'wrap'} gap={1}>
<Stack>
<FormControl sx={{ width: 250 }}>
<OutlinedInput
sx={{ background: 'white' }}
size="medium"
id="header-search"
startAdornment={
<InputAdornment position="start" sx={{ mr: -0.5 }}>
<SearchOutlined />
</InputAdornment>
}
endAdornment={
showClose && (
<InputAdornment position="end" sx={{ mr: -0.5 }}>
<CloseOutlined
onClick={() => {
setSearchword('');
SetShowClose(false);
}}
/>
</InputAdornment>
)
}
aria-describedby="header-search-text"
inputProps={{
'aria-label': 'weight'
}}
placeholder="Search"
value={searchword}
onChange={(e) => {
setSearchword(e.target.value);
if (e.target.value == '') {
SetShowClose(false);
} else {
SetShowClose(true);
}
}}
autoComplete="off"
/>
</FormControl>{' '}
</Stack>
<Stack flexDirection="row" alignItems="center" gap={2}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DatePicker
label="Choose Date"
value={dayjs(startdate)}
format="DD-MM-YYYY"
onChange={(e) => {
if (e) {
setStartdate(dayjs(e.$d).format('YYYY-MM-DD'));
}
}}
/>
</LocalizationProvider>
</Stack>
</Stack>
}
>
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell>S.No</TableCell>
<TableCell>ID</TableCell>
<TableCell>Rider</TableCell>
<TableCell>LogDate</TableCell>
<TableCell>Shift(HRS)</TableCell>
<TableCell>Login</TableCell>
<TableCell>Logout</TableCell>
<TableCell>WRK(HRS)</TableCell>
<TableCell>Shift(HRS)</TableCell>
<TableCell>BRK(HRS)</TableCell>
<TableCell>Status</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.length == 0 ? (
<TableRow>
<TableCell colSpan={11}>
<Empty />
</TableCell>
</TableRow>
) : (
rows.map((row, index) => (
<TableRow key={index + 1}>
<TableCell align="left">{index + 1}</TableCell>
<TableCell align="left">{row.userid}</TableCell>
<TableCell align="left">{row.username}</TableCell>
<TableCell align="left">
{' '}
<Chip label={formatDate(row.logdate)} color="warning" variant="outlined" size="small" sx={{ bgcolor: '#fffde7' }} />
</TableCell>
<TableCell align="left">{row.shifthours}</TableCell>
<TableCell align="left">
{row.login != '' && (
<Chip label={formatTime(row.login)} color="info" variant="outlined" size="small" sx={{ bgcolor: '#e0f7fa' }} />
)}
</TableCell>
<TableCell align="left">
{row.logout != '' && (
<Chip label={formatTime(row.logout)} color="info" variant="outlined" size="small" sx={{ bgcolor: '#e0f7fa' }} />
)}
</TableCell>
<TableCell align="left">{row.workhours}</TableCell>
<TableCell align="left">{row.shorthours}</TableCell>
<TableCell align="left">{row.breakhours}</TableCell>
<TableCell align="left">
{row.logstatus == 0 ? (
<Chip label="Active" color="success" variant="outlined" size="small" sx={{ bgcolor: '#e8f5e9' }} />
) : (
<Chip label="Inactive" color="error" variant="outlined" size="small" sx={{ bgcolor: '#fce4ec' }} />
)}
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</TableContainer>
</MainCard>
</>
);
}

View File

@@ -23,8 +23,6 @@ import {
IconButton, IconButton,
Tooltip, Tooltip,
Chip, Chip,
Autocomplete,
TextField,
Collapse Collapse
} from '@mui/material'; } from '@mui/material';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
@@ -45,12 +43,12 @@ import {
startOfWeek startOfWeek
// startOfYear, // startOfYear,
} from 'date-fns'; } from 'date-fns';
import { FilterList } from '@mui/icons-material';
// project imports // project imports
import MainCard from 'components/MainCard'; import MainCard from 'components/MainCard';
import Loader from 'components/Loader'; import Loader from 'components/Loader';
import TitleCard from '../titleCard'; import TitleCard from '../titleCard';
import { fetchRidersSummary } from '../api/api'; import { fetchRidersSummary } from '../api/api';
import { useTheme } from '@mui/material/styles';
// table filter // table filter
function descendingComparator(a, b, orderBy) { function descendingComparator(a, b, orderBy) {
@@ -88,6 +86,8 @@ function formatNumberToRupees(value) {
export default function RidersSummary() { export default function RidersSummary() {
// const [rows, setRows] = useState([]); // const [rows, setRows] = useState([]);
const theme = useTheme();
const tenantid = localStorage.getItem('tenantid');
const [order, setOrder] = useState('asc'); const [order, setOrder] = useState('asc');
const [orderBy, setOrderBy] = useState('calories'); const [orderBy, setOrderBy] = useState('calories');
const [selected, setSelected] = useState([]); const [selected, setSelected] = useState([]);
@@ -141,9 +141,12 @@ export default function RidersSummary() {
data: rows, data: rows,
error: reportsError error: reportsError
} = useQuery({ } = useQuery({
queryKey: [appId, startdate, enddate], queryKey: [tenantid, startdate, enddate],
queryFn: fetchRidersSummary queryFn: fetchRidersSummary
}); });
useEffect(() => {
rows && console.log('rows', rows);
}, [rows]);
// ==============================|| calculate||============================== // // ==============================|| calculate||============================== //
const calculate = async () => { const calculate = async () => {
let calculatedTotal = 0; let calculatedTotal = 0;
@@ -157,7 +160,7 @@ export default function RidersSummary() {
console.log('calculatedTotal', calculatedTotal); console.log('calculatedTotal', calculatedTotal);
}; };
useEffect(() => { useEffect(() => {
calculate(); rows && calculate();
}, [rows]); }, [rows]);
if (isLoadingReports) return <Loader />; if (isLoadingReports) return <Loader />;
@@ -167,7 +170,8 @@ export default function RidersSummary() {
const fetchTenantSummary = async (riderUserid) => { const fetchTenantSummary = async (riderUserid) => {
try { try {
const tenantRes = await axios.get( const tenantRes = await axios.get(
`${process.env.REACT_APP_URL}/deliveries/getreportsummary/?&fromdate=${startdate}&todate=${enddate}&userid=${riderUserid}` // `${process.env.REACT_APP_URL}/deliveries/getreportlocationsummary/?&fromdate=${startdate}&todate=${enddate}&userid=${riderUserid}&tenantid=${tenantid}`
`${process.env.REACT_APP_URL}/deliveries/getriderlocationreportsummary/?&fromdate=${startdate}&todate=${enddate}&userid=${riderUserid}&tenantid=${tenantid}`
); );
console.log('tenantRes', tenantRes.data.details); console.log('tenantRes', tenantRes.data.details);
setTenantData(tenantRes.data.details); setTenantData(tenantRes.data.details);
@@ -176,42 +180,9 @@ export default function RidersSummary() {
} }
}; };
const handleClick = (event, name) => {
const selectedIndex = selected.indexOf(name);
let newSelected = [];
if (selectedIndex === -1) {
newSelected = newSelected.concat(selected, name);
} else if (selectedIndex === 0) {
newSelected = newSelected.concat(selected.slice(1));
} else if (selectedIndex === selected.length - 1) {
newSelected = newSelected.concat(selected.slice(0, -1));
} else if (selectedIndex > 0) {
newSelected = newSelected.concat(selected.slice(0, selectedIndex), selected.slice(selectedIndex + 1));
}
const selectedRowData = rows.filter((row) => newSelected.includes(row.name));
setSelectedValue(selectedRowData);
setSelected(newSelected);
};
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event?.target.value, 10));
setPage(0);
};
const isSelected = (name) => selected.indexOf(name) !== -1;
// Avoid a layout jump when reaching the last page with empty rows.
const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - rows.length) : 0;
return ( return (
<> <>
<TitleCard title="Riders Summary" /> <TitleCard title="Riders Summary" />
<MainCard <MainCard
content={false} content={false}
title={ title={
@@ -249,15 +220,19 @@ export default function RidersSummary() {
<Table> <Table>
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell>S.No </TableCell> <TableCell># </TableCell>
<TableCell> Rider</TableCell> <TableCell> Rider</TableCell>
<TableCell> Deliveries</TableCell> <TableCell>Total </TableCell>
{/* <TableCell> Pending</TableCell>
<TableCell> Assigned</TableCell> <TableCell> Assigned</TableCell>
<TableCell> Accepted</TableCell> <TableCell> Accepted</TableCell>
<TableCell>Arrived </TableCell>
<TableCell>Picked </TableCell> <TableCell>Picked </TableCell>
<TableCell>Active </TableCell>
<TableCell>Skipped </TableCell> */}
<TableCell>Delivered </TableCell> <TableCell>Delivered </TableCell>
<TableCell>KMS/Actualkms </TableCell> <TableCell>kms </TableCell>
<TableCell> POD/PLA</TableCell> <TableCell> COD/PLA</TableCell>
<TableCell> Charges</TableCell> <TableCell> Charges</TableCell>
<TableCell>Action </TableCell> <TableCell>Action </TableCell>
</TableRow> </TableRow>
@@ -265,7 +240,7 @@ export default function RidersSummary() {
{/* ============================================ || TableBody || ============================================ */} {/* ============================================ || TableBody || ============================================ */}
<TableBody> <TableBody>
{rows.length === 0 && ( {/* {rows?.length === 0 && (
<TableRow> <TableRow>
<TableCell colSpan={11}> <TableCell colSpan={11}>
<Stack width={'100%'} direction={'row'} justifyContent={'center'}> <Stack width={'100%'} direction={'row'} justifyContent={'center'}>
@@ -273,37 +248,18 @@ export default function RidersSummary() {
</Stack> </Stack>
</TableCell> </TableCell>
</TableRow> </TableRow>
)} )} */}
{stableSort(rows, getComparator(order, orderBy)) {rows?.map((row, index) => (
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row, index) => {
if (typeof row === 'number') return null;
const isItemSelected = isSelected(row.name);
const labelId = `enhanced-table-checkbox-${index}`;
return (
rows.length !== 0 && (
<> <>
{/* // ============================================ || tablerow 1 || ============================================ */} {/* // ============================================ || tablerow 1 || ============================================ */}
<TableRow <TableRow
hover
onClick={(event) => handleClick(event, row.name)}
role="checkbox"
aria-checked={isItemSelected}
tabIndex={-1}
key={row.tenantname}
selected={isItemSelected}
sx={{ sx={{
bgcolor: openRow === row.userid ? '#e1bee7' : null,
'&:hover': {
bgcolor: openRow === row.userid ? '#e1bee7!important' : null
},
cursor: openRow === row.userid ? 'pointer' : null cursor: openRow === row.userid ? 'pointer' : null
}} }}
> >
<TableCell component="th" id={labelId} scope="row" padding="none"> <TableCell component="th" scope="row" padding="none">
{index + 1} {index + 1}
</TableCell> </TableCell>
<TableCell align="left"> <TableCell align="left">
@@ -316,14 +272,35 @@ export default function RidersSummary() {
)} )}
</Stack> </Stack>
</TableCell> </TableCell>
<TableCell align="left">{row.deliveries}</TableCell>
<TableCell align="left">{row.Assigened}</TableCell> <TableCell align="left">{row.totalorders}</TableCell>
<TableCell align="left">{row.Accepted}</TableCell> {/* <TableCell align="left">
<TableCell align="left">{row.Picked}</TableCell> {row.pending ? <Chip color="primary" variant="light" label={row.pending} /> : row.pending}
</TableCell>
<TableCell align="left">
{row.assigned ? <Chip color="primary" variant="light" label={row.assigned} /> : row.assigned}
</TableCell>
<TableCell align="left">
{row.accepted ? <Chip color="primary" variant="light" label={row.accepted} /> : row.accepted}
</TableCell>
<TableCell align="left">
{row.arrived ? <Chip color="primary" variant="light" label={row.arrived} /> : row.arrived}
</TableCell>
<TableCell align="left">
{row.picked ? <Chip color="primary" variant="light" label={row.picked} /> : row.picked}
</TableCell>
<TableCell align="left">
{row.active ? <Chip color="primary" variant="light" label={row.active} /> : row.active}
</TableCell>
<TableCell align="left">
{row.skipped ? <Chip color="primary" variant="light" label={row.skipped} /> : row.skipped}
</TableCell> */}
<TableCell align="left">{row.delivered}</TableCell> <TableCell align="left">{row.delivered}</TableCell>
<TableCell align="left"> <TableCell align="left">
<Stack direction={'row'}> <Stack direction={'row'}>
<Tooltip title="kms" placement="top"> {/* <Tooltip title="kms" placement="top">
<Chip <Chip
size="small" size="small"
label={row.kms} label={row.kms}
@@ -336,7 +313,7 @@ export default function RidersSummary() {
minWidth: 80 minWidth: 80
}} }}
/> />
</Tooltip> </Tooltip> */}
<Tooltip title="Actual kms" placement="bottom"> <Tooltip title="Actual kms" placement="bottom">
<Chip <Chip
size="small" size="small"
@@ -383,15 +360,15 @@ export default function RidersSummary() {
</Tooltip> </Tooltip>
</Stack> </Stack>
</TableCell> </TableCell>
<TableCell align="right"> <TableCell align="left">
<Tooltip title="Total Charges" placement="top"> <Tooltip title="Total Charges" placement="top">
<Chip <Chip
size="small" size="small"
label={formatNumberToRupees(row.Deliveryamt)} label={formatNumberToRupees(row.deliveryamt)}
sx={{ sx={{
color: 'primary.main', color: '#1976d2',
bgcolor: '#e1bee7', bgcolor: '#e3f2fd',
border: '1px solid #662582 ', border: '1px solid #1976d2',
cursor: 'pointer', cursor: 'pointer',
minWidth: 100 minWidth: 100
}} }}
@@ -422,79 +399,63 @@ export default function RidersSummary() {
{openRow === row.userid && ( {openRow === row.userid && (
<TableRow <TableRow
sx={{ sx={{
bgcolor: openRow === row.userid ? '#f3e5f5' : null, bgcolor: openRow === row.userid ? 'white' : null,
'&:hover': { '&:hover': {
bgcolor: openRow === row.userid ? '#f3e5f5!important' : null bgcolor: openRow === row.userid ? 'white!important' : null
}, },
cursor: openRow === row.userid ? 'pointer' : null cursor: openRow === row.userid ? 'pointer' : null
}} }}
> >
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={15}> <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={15}>
<Collapse <Collapse in={true} timeout="auto" unmountOnExit>
// in={openRow[row.tenantname]}
in={true}
timeout="auto"
unmountOnExit
>
<Box sx={{ margin: 1 }}> <Box sx={{ margin: 1 }}>
<Typography variant="h5" gutterBottom component="div">
Tenant Summary
</Typography>
<Table size="small" aria-label="purchases"> <Table size="small" aria-label="purchases">
<TableHead <TableHead>
<TableRow
sx={{ sx={{
bgcolor: '#f3e5f5', bgcolor: theme.palette.secondary.lighter,
'&:onhover': {
bgcolor: '#f3e5f5!important' '&:hover': {
bgcolor: `${theme.palette.secondary.lighter} !important`
} }
}} }}
> >
<TableRow>
<TableCell>#</TableCell> <TableCell>#</TableCell>
<TableCell>Client</TableCell> <TableCell>Location</TableCell>
<TableCell align="left">All</TableCell> <TableCell align="left">All</TableCell>
<TableCell align="left">Pending</TableCell> {/* <TableCell align="left">Pending</TableCell> */}
<TableCell align="left">Completed</TableCell> <TableCell align="left">Completed</TableCell>
<TableCell align="left">Cancelled</TableCell> {/* <TableCell align="left">Cancelled</TableCell> */}
<TableCell align="center">Kms/Actual Kms</TableCell> <TableCell align="left">Actual Kms</TableCell>
<TableCell align="center">POD / PLA</TableCell> <TableCell align="left">COD / PLA</TableCell>
<TableCell align="center">Amount</TableCell> <TableCell align="left">Amount</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{tenantData.map((row, index) => ( {tenantData?.map((row, index) => (
<TableRow <TableRow
hover sx={{
onClick={(event) => handleClick(event, row.name)} bgcolor: 'white!important',
role="checkbox" '&:onhover': {
aria-checked={isItemSelected} bgcolor: 'white!important'
tabIndex={-1} }
key={row.tenantname}
selected={isItemSelected}
>
{/* <TableCell sx={{ pl: 3 }} padding="checkbox">
<Checkbox
color="primary"
checked={isItemSelected}
inputProps={{
"aria-labelledby": labelId,
}} }}
/> key={row.tenantname}
</TableCell> */} >
<TableCell component="th" id={labelId} scope="row" padding="none"> <TableCell component="th" scope="row" padding="none">
{index + 1} {index + 1}
</TableCell> </TableCell>
<TableCell align="left"> <TableCell align="left">
<Stack direction="row" sx={{ ml: -2 }}> <Stack direction="row" sx={{ ml: -2 }}>
{row.tenantname} {row.locationname}
</Stack> </Stack>
</TableCell> </TableCell>
<TableCell align="left">{row.totalorders}</TableCell> <TableCell align="left">{row.totalorders}</TableCell>
<TableCell align="left">{row.deliveriespending}</TableCell> {/* <TableCell align="left">{row.deliveriespending}</TableCell> */}
<TableCell align="left">{row.deliveriescompleted}</TableCell> <TableCell align="left">{row.deliveriescompleted}</TableCell>
<TableCell align="left">{row.deliveriescancelled}</TableCell> {/* <TableCell align="left">{row.deliveriescancelled}</TableCell> */}
<TableCell align="center"> <TableCell align="left">
<Chip {/* <Chip
size="small" size="small"
label={row.kms} label={row.kms}
sx={{ sx={{
@@ -504,7 +465,7 @@ export default function RidersSummary() {
border: '1px solid #1976d2', border: '1px solid #1976d2',
minWidth: 80 minWidth: 80
}} }}
/> /> */}
<Chip <Chip
size="small" size="small"
label={row.actualkms} label={row.actualkms}
@@ -517,7 +478,7 @@ export default function RidersSummary() {
/> />
</TableCell> </TableCell>
<TableCell align="center"> <TableCell align="left">
<Chip <Chip
size="small" size="small"
label={formatNumberToRupees(row.payondelivery)} label={formatNumberToRupees(row.payondelivery)}
@@ -540,7 +501,7 @@ export default function RidersSummary() {
/> />
</TableCell> </TableCell>
<TableCell align="center"> <TableCell align="left">
<Chip <Chip
size="small" size="small"
label={formatNumberToRupees(row.charges)} label={formatNumberToRupees(row.charges)}
@@ -562,35 +523,19 @@ export default function RidersSummary() {
</TableRow> </TableRow>
)} )}
</> </>
) ))}
);
})}
{emptyRows > 0 && (
<TableRow sx={{ height: (dense ? 33 : 53) * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
<Divider /> <Divider />
<Stack direction={'row'} sx={{ display: 'flex', justifyContent: 'end', px: 1, py: 2 }}> {/* <Stack direction={'row'} sx={{ display: 'flex', justifyContent: 'end', px: 1, py: 2 }}>
<Typography variant="h5">Total :</Typography> <Typography variant="h5">Total :</Typography>
<Typography variant="h5" sx={{ ml: 5, mr: 1.5 }}> <Typography variant="h5" sx={{ ml: 5, mr: 1.5 }}>
{formatNumberToRupees(total)} {formatNumberToRupees(total)}
</Typography> </Typography>
</Stack> </Stack> */}
{/* table pagination */}
{/* <TablePagination
rowsPerPageOptions={[10, 25, 50]}
component="div"
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/> */}
</MainCard> </MainCard>
{/* ================================================ || Date Filter || ================================================ */}
<Dialog open={open}> <Dialog open={open}>
<DialogTitle align="left"> <DialogTitle align="left">
<Typography variant="h4">Select Filter Options</Typography> <Typography variant="h4">Select Filter Options</Typography>
@@ -605,7 +550,6 @@ export default function RidersSummary() {
setDateselect('all'); setDateselect('all');
setStartdate(''); setStartdate('');
setEnddate(''); setEnddate('');
setOpen(false); setOpen(false);
} else { } else {
setDateselect('select'); setDateselect('select');

View File

@@ -20,7 +20,7 @@ import {
Button, Button,
List List
} from '@mui/material'; } from '@mui/material';
const TitleCard = ({ title }) => { const TitleCard = ({ title, secondary, sx }) => {
const theme = useTheme(); const theme = useTheme();
return ( return (
<Grid container spacing={2}> <Grid container spacing={2}>
@@ -32,12 +32,14 @@ const TitleCard = ({ title }) => {
bgcolor: theme.palette.background.default, bgcolor: theme.palette.background.default,
zIndex: 1, zIndex: 1,
// borderBottom: `1px solid ${theme.palette.divider}`, // borderBottom: `1px solid ${theme.palette.divider}`,
width: '100%' width: '100%',
...sx
}} }}
> >
<Grid item xs={12}> <Grid item xs={12}>
<Stack direction={'row'} justifyContent={'space-between'} sx={{ p: 1 }}> <Stack direction={'row'} justifyContent={'space-between'} sx={{ p: 1, flexWrap: 'wrap' }}>
<Typography variant="h3">{title}</Typography> <Typography variant="h3">{title}</Typography>
{secondary && secondary}
</Stack> </Stack>
</Grid> </Grid>
</CardActions> </CardActions>

View File

@@ -19,6 +19,8 @@ const Login = Loadable(lazy(() => import('pages/nearle/login')));
const Customers = Loadable(lazy(() => import('pages/nearle/clients/customers'))); const Customers = Loadable(lazy(() => import('pages/nearle/clients/customers')));
const Locations = Loadable(lazy(() => import('pages/nearle/locations/Locations')));
const Orders = Loadable(lazy(() => import('pages/nearle/orders/orders'))); const Orders = Loadable(lazy(() => import('pages/nearle/orders/orders')));
const Details = Loadable(lazy(() => import('pages/nearle/orders/details'))); const Details = Loadable(lazy(() => import('pages/nearle/orders/details')));
@@ -56,16 +58,18 @@ const MainRoutes = {
children: [ children: [
{ {
path: 'orders', path: 'orders',
element: <Orders />,
children: [ children: [
// use Outlet in orders page to render the child, because order render in app, but chidren createorder, multipleorder have nowhere, outlet make parent as to render {
path: '', // /orders
element: <Orders />
},
{
path: 'create/grouporders', // /orders/create/grouporders
element: <MultipleOrders />
},
{ {
path: 'create', path: 'create',
element: <Createorder1 /> element: <Createorder1 />
},
{
path: 'createorders',
element: <MultipleOrders />
} }
] ]
}, },
@@ -115,6 +119,10 @@ const MainRoutes = {
element: <InvoicePreview /> element: <InvoicePreview />
} }
] ]
},
{
path: 'locations',
element: <Locations />
} }
] ]
}, },

View File

@@ -27,11 +27,30 @@ export default function ThemeCustomization({ children }) {
() => ({ () => ({
breakpoints: { breakpoints: {
values: { values: {
xs: 0, xs: 0, // Extra-small: 0px and up
sm: 768, custom300: 300, // above 350
md: 1024, custom350: 350, // above 350
lg: 1266, custom400: 400, // above 400
xl: 1440 custom450: 450, // above 450
custom500: 500, // above 450
custom550: 550, // above 450
custom600: 600, // above 450
custom650: 650, // above 450
custom700: 700, // above 450
custom750: 750, // above 450
sm: 768, // Small: 768px and up
custom800: 800, // above 450,
custom850: 850, // above 450,
custom900: 900, // above 450
custom950: 950, // above 450
custom1000: 1000, // above 450
md: 1024, // Medium: 1024px and up
custom1050: 1050, //
custom1100: 1100, //
lg: 1266, // Large: 1266px and up
custom1300: 1300, // Large: 1266px and up
custom1350: 1350, // Large: 1266px and up
xl: 1440 // Extra-large: 1440px and up
} }
}, },
direction: themeDirection, direction: themeDirection,

View File

@@ -40,17 +40,17 @@ const Default = (colors) => {
// contrastText // contrastText
// }, // },
primary: { primary: {
lighter: purple[0], lighter: '#E8D9EF',
100: purple[1], 100: '#CBA7DA',
200: purple[2], 200: '#AE76C4',
light: purple[3], light: '#9255AB',
400: purple[4], 400: '#9255AB',
main: '#662582', main: '#662582',
dark: purple[6], dark: '#4D1C61',
700: purple[7], 700: '#3A1549',
darker: purple[8], darker: '#260E30',
900: purple[9], 900: '#17081D',
contrastText contrastText: '#FFFFFF'
}, },
secondary: { secondary: {
lighter: greyColors[100], lighter: greyColors[100],
@@ -105,7 +105,11 @@ const Default = (colors) => {
darker: green[9], darker: green[9],
contrastText contrastText
}, },
grey: greyColors grey: greyColors,
bg: {
main: '#E0E0E0',
light: '#fafafb'
}
}; };
}; };

View File

@@ -1243,6 +1243,11 @@
resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz" resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz"
integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA== integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==
"@custom-react-hooks/use-network@^1.0.1":
version "1.0.1"
resolved "https://registry.npmjs.org/@custom-react-hooks/use-network/-/use-network-1.0.1.tgz"
integrity sha512-WbFVxsC18hjJiVIONAExVORlJlrOeYwzKsiYUCzrt5zCP0u9eLUPJuftF3DvEpoaQdjufazllWCPWKXT+dTY2g==
"@emotion/babel-plugin@^11.10.6": "@emotion/babel-plugin@^11.10.6":
version "11.10.6" version "11.10.6"
resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz" resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz"
@@ -1501,6 +1506,19 @@
intl-messageformat "10.3.4" intl-messageformat "10.3.4"
tslib "^2.4.0" tslib "^2.4.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": "@humanwhocodes/config-array@^0.11.8":
version "0.11.8" version "0.11.8"
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz" resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz"
@@ -2069,6 +2087,28 @@
resolved "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz" resolved "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz"
integrity sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA== integrity sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==
"@react-google-maps/api@^2.20.7":
version "2.20.7"
resolved "https://registry.npmjs.org/@react-google-maps/api/-/api-2.20.7.tgz"
integrity sha512-ys7uri3V6gjhYZUI43srHzSKDC6/jiKTwHNlwXFTvjeaJE3M3OaYBt9FZKvJs8qnOhL6i6nD1BKJoi1KrnkCkg==
dependencies:
"@googlemaps/js-api-loader" "1.16.8"
"@googlemaps/markerclusterer" "2.5.3"
"@react-google-maps/infobox" "2.20.0"
"@react-google-maps/marker-clusterer" "2.20.0"
"@types/google.maps" "3.58.1"
invariant "2.2.4"
"@react-google-maps/infobox@2.20.0":
version "2.20.0"
resolved "https://registry.npmjs.org/@react-google-maps/infobox/-/infobox-2.20.0.tgz"
integrity sha512-03PJHjohhaVLkX6+NHhlr8CIlvUxWaXhryqDjyaZ8iIqqix/nV8GFdz9O3m5OsjtxtNho09F/15j14yV0nuyLQ==
"@react-google-maps/marker-clusterer@2.20.0":
version "2.20.0"
resolved "https://registry.npmjs.org/@react-google-maps/marker-clusterer/-/marker-clusterer-2.20.0.tgz"
integrity sha512-tieX9Va5w1yP88vMgfH1pHTacDQ9TgDTjox3tLlisKDXRQWdjw+QeVVghhf5XqqIxXHgPdcGwBvKY6UP+SIvLw==
"@react-leaflet/core@^2.1.0": "@react-leaflet/core@^2.1.0":
version "2.1.0" version "2.1.0"
resolved "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz" resolved "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz"
@@ -2503,6 +2543,11 @@
"@types/qs" "*" "@types/qs" "*"
"@types/serve-static" "*" "@types/serve-static" "*"
"@types/google.maps@3.58.1":
version "3.58.1"
resolved "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.58.1.tgz"
integrity sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==
"@types/graceful-fs@^4.1.2": "@types/graceful-fs@^4.1.2":
version "4.1.5" version "4.1.5"
resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz" resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz"
@@ -6238,6 +6283,13 @@ intl-messageformat@10.3.4:
"@formatjs/icu-messageformat-parser" "2.3.1" "@formatjs/icu-messageformat-parser" "2.3.1"
tslib "^2.4.0" tslib "^2.4.0"
invariant@2.2.4:
version "2.2.4"
resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
dependencies:
loose-envify "^1.0.0"
ipaddr.js@^2.0.1: ipaddr.js@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz"
@@ -7199,6 +7251,11 @@ jwt-decode@^3.1.2:
resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz" resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz"
integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==
kdbush@^4.0.2:
version "4.0.2"
resolved "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz"
integrity sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==
kind-of@^6.0.2: kind-of@^6.0.2:
version "6.0.3" version "6.0.3"
resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
@@ -7343,7 +7400,7 @@ lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
loose-envify@^1.1.0, loose-envify@^1.4.0: loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -9186,7 +9243,7 @@ react-dnd@^16.0.1:
fast-deep-equal "^3.1.3" fast-deep-equal "^3.1.3"
hoist-non-react-statics "^3.3.2" hoist-non-react-statics "^3.3.2"
react-dom@*, "react-dom@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^17.0.0 || ^18.0.0", react-dom@^17.0.2, react-dom@^18.0.0, react-dom@^18.2.0, "react-dom@>= 0.14.0", "react-dom@>=16 || >=17 || >= 18", react-dom@>=16.0.0, react-dom@>=16.11.0, react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=16.8.0, react-dom@>=16.9.0, "react-dom@16.2.0 - 18": react-dom@*, "react-dom@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8 || ^17 || ^18 || ^19", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^17.0.0 || ^18.0.0", react-dom@^17.0.2, react-dom@^18.0.0, react-dom@^18.2.0, "react-dom@>= 0.14.0", "react-dom@>=16 || >=17 || >= 18", react-dom@>=16.0.0, react-dom@>=16.11.0, react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=16.8.0, react-dom@>=16.9.0, "react-dom@16.2.0 - 18":
version "18.2.0" version "18.2.0"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
@@ -9400,7 +9457,7 @@ react-virtuoso@^4.7.0:
resolved "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.7.0.tgz" resolved "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.7.0.tgz"
integrity sha512-cpgvI1rSOETGDMhqVAVDuH+XHbWO1uIGKv5I6l4CyC71xWYUeGrE5n7sgTZklROB4+Vbv85pcgfWloTlY48HGQ== integrity sha512-cpgvI1rSOETGDMhqVAVDuH+XHbWO1uIGKv5I6l4CyC71xWYUeGrE5n7sgTZklROB4+Vbv85pcgfWloTlY48HGQ==
react@*, "react@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.6.0 || 17 || 18", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.9.0 || ^17.0.0 || ^18", "react@^17.0.0 || ^18.0.0", react@^17.0.2, react@^18.0.0, react@^18.2.0, "react@>= 0.14.0", "react@>= 16", "react@>= 16.14", "react@>=16 || >=17 || >= 18", react@>=16.0.0, react@>=16.11.0, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=16.9.0, "react@16.2.0 - 18": react@*, "react@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.6.0 || 17 || 18", "react@^16.8 || ^17 || ^18 || ^19", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.9.0 || ^17.0.0 || ^18", "react@^17.0.0 || ^18.0.0", react@^17.0.2, react@^18.0.0, react@^18.2.0, "react@>= 0.14.0", "react@>= 16", "react@>= 16.14", "react@>=16 || >=17 || >= 18", react@>=16.0.0, react@>=16.11.0, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=16.9.0, "react@16.2.0 - 18":
version "18.2.0" version "18.2.0"
resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
@@ -10293,6 +10350,13 @@ stylis@^4.0.13, stylis@4.1.3, stylis@4.x:
resolved "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz" resolved "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz"
integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== 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: supports-color@^5.3.0:
version "5.5.0" version "5.5.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"