Complete Landing Page and APi Integration for Dashboard
158
pnpm-lock.yaml
|
@ -21,8 +21,8 @@ importers:
|
||||||
specifier: ^6.4.5
|
specifier: ^6.4.5
|
||||||
version: 6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
'@mui/x-charts':
|
'@mui/x-charts':
|
||||||
specifier: ^7.27.0
|
specifier: ^7.27.1
|
||||||
version: 7.27.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@mui/material@6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 7.28.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@mui/material@6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
'@mui/x-data-grid':
|
'@mui/x-data-grid':
|
||||||
specifier: ^7.27.0
|
specifier: ^7.27.0
|
||||||
version: 7.27.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@mui/material@6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 7.27.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@mui/material@6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
@ -80,6 +80,9 @@ importers:
|
||||||
react-hook-form:
|
react-hook-form:
|
||||||
specifier: ^7.54.2
|
specifier: ^7.54.2
|
||||||
version: 7.54.2(react@18.3.1)
|
version: 7.54.2(react@18.3.1)
|
||||||
|
react-minimal-pie-chart:
|
||||||
|
specifier: ^9.1.0
|
||||||
|
version: 9.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
react-redux:
|
react-redux:
|
||||||
specifier: ^9.2.0
|
specifier: ^9.2.0
|
||||||
version: 9.2.0(@types/react@19.0.10)(react@18.3.1)(redux@5.0.1)
|
version: 9.2.0(@types/react@19.0.10)(react@18.3.1)(redux@5.0.1)
|
||||||
|
@ -89,6 +92,9 @@ importers:
|
||||||
react-scripts:
|
react-scripts:
|
||||||
specifier: 5.0.1
|
specifier: 5.0.1
|
||||||
version: 5.0.1(@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.9))(@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.9))(@types/babel__core@7.20.5)(eslint@8.57.1)(react@18.3.1)(type-fest@0.21.3)(typescript@5.7.3)
|
version: 5.0.1(@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.9))(@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.9))(@types/babel__core@7.20.5)(eslint@8.57.1)(react@18.3.1)(type-fest@0.21.3)(typescript@5.7.3)
|
||||||
|
recharts:
|
||||||
|
specifier: ^2.15.1
|
||||||
|
version: 2.15.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
sonner:
|
sonner:
|
||||||
specifier: ^1.7.4
|
specifier: ^1.7.4
|
||||||
version: 1.7.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 1.7.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
@ -1203,14 +1209,14 @@ packages:
|
||||||
'@mui/x-charts-vendor@7.20.0':
|
'@mui/x-charts-vendor@7.20.0':
|
||||||
resolution: {integrity: sha512-pzlh7z/7KKs5o0Kk0oPcB+sY0+Dg7Q7RzqQowDQjpy5Slz6qqGsgOB5YUzn0L+2yRmvASc4Pe0914Ao3tMBogg==}
|
resolution: {integrity: sha512-pzlh7z/7KKs5o0Kk0oPcB+sY0+Dg7Q7RzqQowDQjpy5Slz6qqGsgOB5YUzn0L+2yRmvASc4Pe0914Ao3tMBogg==}
|
||||||
|
|
||||||
'@mui/x-charts@7.27.0':
|
'@mui/x-charts@7.28.0':
|
||||||
resolution: {integrity: sha512-EIT5zbClc8n14qBvCD7jYSVI4jWAWajY7g8gznf5rggCJuv08IHfmi23q6afax73q6yTAi30qeUmcqttqXV4DQ==}
|
resolution: {integrity: sha512-TNfq/rQfGKnjTaEITkY6l09NpMxwMwRTgLiDw+JQsS/7gwBBJUmMhEOj67BaFeYTsroFLUYeggiAj+RTSryd4A==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@emotion/react': ^11.9.0
|
'@emotion/react': ^11.9.0
|
||||||
'@emotion/styled': ^11.8.1
|
'@emotion/styled': ^11.8.1
|
||||||
'@mui/material': ^5.15.14 || ^6.0.0
|
'@mui/material': ^5.15.14 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta
|
||||||
'@mui/system': ^5.15.14 || ^6.0.0
|
'@mui/system': ^5.15.14 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta
|
||||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
|
@ -1278,6 +1284,12 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
|
'@mui/x-internals@7.28.0':
|
||||||
|
resolution: {integrity: sha512-p4GEp/09bLDumktdIMiw+OF4p+pJOOjTG0VUvzNxjbHB9GxbBKoMcHrmyrURqoBnQpWIeFnN/QAoLMFSpfwQbw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
'@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1':
|
'@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1':
|
||||||
resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==}
|
resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==}
|
||||||
|
|
||||||
|
@ -1501,12 +1513,18 @@ packages:
|
||||||
'@types/cookie@0.6.0':
|
'@types/cookie@0.6.0':
|
||||||
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
||||||
|
|
||||||
|
'@types/d3-array@3.2.1':
|
||||||
|
resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==}
|
||||||
|
|
||||||
'@types/d3-color@3.1.3':
|
'@types/d3-color@3.1.3':
|
||||||
resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
|
resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
|
||||||
|
|
||||||
'@types/d3-delaunay@6.0.4':
|
'@types/d3-delaunay@6.0.4':
|
||||||
resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==}
|
resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==}
|
||||||
|
|
||||||
|
'@types/d3-ease@3.0.2':
|
||||||
|
resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==}
|
||||||
|
|
||||||
'@types/d3-interpolate@3.0.4':
|
'@types/d3-interpolate@3.0.4':
|
||||||
resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
|
resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
|
||||||
|
|
||||||
|
@ -1522,6 +1540,9 @@ packages:
|
||||||
'@types/d3-time@3.0.4':
|
'@types/d3-time@3.0.4':
|
||||||
resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==}
|
resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==}
|
||||||
|
|
||||||
|
'@types/d3-timer@3.0.2':
|
||||||
|
resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
|
||||||
|
|
||||||
'@types/eslint-scope@3.7.7':
|
'@types/eslint-scope@3.7.7':
|
||||||
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
|
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
|
||||||
|
|
||||||
|
@ -2483,6 +2504,10 @@ packages:
|
||||||
resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==}
|
resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
d3-ease@3.0.1:
|
||||||
|
resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
d3-format@3.1.0:
|
d3-format@3.1.0:
|
||||||
resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
|
resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -2511,6 +2536,10 @@ packages:
|
||||||
resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
|
resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
d3-timer@3.0.1:
|
||||||
|
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
damerau-levenshtein@1.0.8:
|
damerau-levenshtein@1.0.8:
|
||||||
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
|
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
|
||||||
|
|
||||||
|
@ -2558,6 +2587,9 @@ packages:
|
||||||
supports-color:
|
supports-color:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
decimal.js-light@2.5.1:
|
||||||
|
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
|
||||||
|
|
||||||
decimal.js@10.5.0:
|
decimal.js@10.5.0:
|
||||||
resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==}
|
resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==}
|
||||||
|
|
||||||
|
@ -2999,6 +3031,10 @@ packages:
|
||||||
fast-deep-equal@3.1.3:
|
fast-deep-equal@3.1.3:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
|
|
||||||
|
fast-equals@5.2.2:
|
||||||
|
resolution: {integrity: sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
fast-glob@3.3.3:
|
fast-glob@3.3.3:
|
||||||
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
|
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
|
||||||
engines: {node: '>=8.6.0'}
|
engines: {node: '>=8.6.0'}
|
||||||
|
@ -4934,6 +4970,12 @@ packages:
|
||||||
react-is@19.0.0:
|
react-is@19.0.0:
|
||||||
resolution: {integrity: sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==}
|
resolution: {integrity: sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==}
|
||||||
|
|
||||||
|
react-minimal-pie-chart@9.1.0:
|
||||||
|
resolution: {integrity: sha512-JziZXZT0aw+9X+rGSpQwbSG7t3ypsyhzJNpiTUGfVeCqr70YIPbHE5Us3RsCsNRlVHbeLGrp/ibVuzUJT6Gcvw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17 || ^18 || ^19
|
||||||
|
react-dom: ^16.8.0 || ^17 || ^18 || ^19
|
||||||
|
|
||||||
react-redux@9.2.0:
|
react-redux@9.2.0:
|
||||||
resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==}
|
resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -4979,6 +5021,12 @@ packages:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
react-smooth@4.0.4:
|
||||||
|
resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
react-transition-group@4.4.5:
|
react-transition-group@4.4.5:
|
||||||
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
|
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -5003,6 +5051,16 @@ packages:
|
||||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||||
engines: {node: '>=8.10.0'}
|
engines: {node: '>=8.10.0'}
|
||||||
|
|
||||||
|
recharts-scale@0.4.5:
|
||||||
|
resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==}
|
||||||
|
|
||||||
|
recharts@2.15.1:
|
||||||
|
resolution: {integrity: sha512-v8PUTUlyiDe56qUj82w/EDVuzEFXwEHp9/xOowGAZwfLjB9uAy3GllQVIYMWF6nU+qibx85WF75zD7AjqoT54Q==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
recursive-readdir@2.2.3:
|
recursive-readdir@2.2.3:
|
||||||
resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==}
|
resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
|
@ -5511,6 +5569,10 @@ packages:
|
||||||
svg-parser@2.0.4:
|
svg-parser@2.0.4:
|
||||||
resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==}
|
resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==}
|
||||||
|
|
||||||
|
svg-partial-circle@1.0.0:
|
||||||
|
resolution: {integrity: sha512-jDWgNzrlpsGo9A7/tdjCy6+1RzeeANYV1a3JtNYC/0ZXI3U+3VMucuNv7JuKti9VVBdyNxNO1CZs/k0xS1lUFA==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
svgo@1.3.2:
|
svgo@1.3.2:
|
||||||
resolution: {integrity: sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==}
|
resolution: {integrity: sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==}
|
||||||
engines: {node: '>=4.0.0'}
|
engines: {node: '>=4.0.0'}
|
||||||
|
@ -5591,6 +5653,9 @@ packages:
|
||||||
thunky@1.1.0:
|
thunky@1.1.0:
|
||||||
resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==}
|
resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==}
|
||||||
|
|
||||||
|
tiny-invariant@1.3.3:
|
||||||
|
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
|
||||||
|
|
||||||
tmpl@1.0.5:
|
tmpl@1.0.5:
|
||||||
resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
|
resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
|
||||||
|
|
||||||
|
@ -5783,6 +5848,9 @@ packages:
|
||||||
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
victory-vendor@36.9.2:
|
||||||
|
resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==}
|
||||||
|
|
||||||
w3c-hr-time@1.0.2:
|
w3c-hr-time@1.0.2:
|
||||||
resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
|
resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
|
||||||
deprecated: Use your platform's native performance.now() and performance.timeOrigin.
|
deprecated: Use your platform's native performance.now() and performance.timeOrigin.
|
||||||
|
@ -7461,14 +7529,14 @@ snapshots:
|
||||||
delaunator: 5.0.1
|
delaunator: 5.0.1
|
||||||
robust-predicates: 3.0.2
|
robust-predicates: 3.0.2
|
||||||
|
|
||||||
'@mui/x-charts@7.27.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@mui/material@6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
'@mui/x-charts@7.28.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@mui/material@6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.9
|
'@babel/runtime': 7.26.9
|
||||||
'@mui/material': 6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
'@mui/material': 6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
'@mui/system': 6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1)
|
'@mui/system': 6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1))(@types/react@19.0.10)(react@18.3.1)
|
||||||
'@mui/utils': 6.4.3(@types/react@19.0.10)(react@18.3.1)
|
'@mui/utils': 6.4.3(@types/react@19.0.10)(react@18.3.1)
|
||||||
'@mui/x-charts-vendor': 7.20.0
|
'@mui/x-charts-vendor': 7.20.0
|
||||||
'@mui/x-internals': 7.26.0(@types/react@19.0.10)(react@18.3.1)
|
'@mui/x-internals': 7.28.0(@types/react@19.0.10)(react@18.3.1)
|
||||||
'@react-spring/rafz': 9.7.5
|
'@react-spring/rafz': 9.7.5
|
||||||
'@react-spring/web': 9.7.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
'@react-spring/web': 9.7.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
clsx: 2.1.1
|
clsx: 2.1.1
|
||||||
|
@ -7528,6 +7596,14 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/react'
|
- '@types/react'
|
||||||
|
|
||||||
|
'@mui/x-internals@7.28.0(@types/react@19.0.10)(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.26.9
|
||||||
|
'@mui/utils': 6.4.3(@types/react@19.0.10)(react@18.3.1)
|
||||||
|
react: 18.3.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@types/react'
|
||||||
|
|
||||||
'@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1':
|
'@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1':
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint-scope: 5.1.1
|
eslint-scope: 5.1.1
|
||||||
|
@ -7773,10 +7849,14 @@ snapshots:
|
||||||
|
|
||||||
'@types/cookie@0.6.0': {}
|
'@types/cookie@0.6.0': {}
|
||||||
|
|
||||||
|
'@types/d3-array@3.2.1': {}
|
||||||
|
|
||||||
'@types/d3-color@3.1.3': {}
|
'@types/d3-color@3.1.3': {}
|
||||||
|
|
||||||
'@types/d3-delaunay@6.0.4': {}
|
'@types/d3-delaunay@6.0.4': {}
|
||||||
|
|
||||||
|
'@types/d3-ease@3.0.2': {}
|
||||||
|
|
||||||
'@types/d3-interpolate@3.0.4':
|
'@types/d3-interpolate@3.0.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/d3-color': 3.1.3
|
'@types/d3-color': 3.1.3
|
||||||
|
@ -7793,6 +7873,8 @@ snapshots:
|
||||||
|
|
||||||
'@types/d3-time@3.0.4': {}
|
'@types/d3-time@3.0.4': {}
|
||||||
|
|
||||||
|
'@types/d3-timer@3.0.2': {}
|
||||||
|
|
||||||
'@types/eslint-scope@3.7.7':
|
'@types/eslint-scope@3.7.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/eslint': 9.6.1
|
'@types/eslint': 9.6.1
|
||||||
|
@ -8899,6 +8981,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
delaunator: 5.0.1
|
delaunator: 5.0.1
|
||||||
|
|
||||||
|
d3-ease@3.0.1: {}
|
||||||
|
|
||||||
d3-format@3.1.0: {}
|
d3-format@3.1.0: {}
|
||||||
|
|
||||||
d3-interpolate@3.0.1:
|
d3-interpolate@3.0.1:
|
||||||
|
@ -8927,6 +9011,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
d3-array: 3.2.4
|
d3-array: 3.2.4
|
||||||
|
|
||||||
|
d3-timer@3.0.1: {}
|
||||||
|
|
||||||
damerau-levenshtein@1.0.8: {}
|
damerau-levenshtein@1.0.8: {}
|
||||||
|
|
||||||
data-urls@2.0.0:
|
data-urls@2.0.0:
|
||||||
|
@ -8967,6 +9053,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
|
||||||
|
decimal.js-light@2.5.1: {}
|
||||||
|
|
||||||
decimal.js@10.5.0: {}
|
decimal.js@10.5.0: {}
|
||||||
|
|
||||||
dedent@0.7.0: {}
|
dedent@0.7.0: {}
|
||||||
|
@ -9570,6 +9658,8 @@ snapshots:
|
||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
|
|
||||||
|
fast-equals@5.2.2: {}
|
||||||
|
|
||||||
fast-glob@3.3.3:
|
fast-glob@3.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nodelib/fs.stat': 2.0.5
|
'@nodelib/fs.stat': 2.0.5
|
||||||
|
@ -11779,6 +11869,12 @@ snapshots:
|
||||||
|
|
||||||
react-is@19.0.0: {}
|
react-is@19.0.0: {}
|
||||||
|
|
||||||
|
react-minimal-pie-chart@9.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
svg-partial-circle: 1.0.0
|
||||||
|
|
||||||
react-redux@9.2.0(@types/react@19.0.10)(react@18.3.1)(redux@5.0.1):
|
react-redux@9.2.0(@types/react@19.0.10)(react@18.3.1)(redux@5.0.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/use-sync-external-store': 0.0.6
|
'@types/use-sync-external-store': 0.0.6
|
||||||
|
@ -11893,6 +11989,14 @@ snapshots:
|
||||||
- webpack-hot-middleware
|
- webpack-hot-middleware
|
||||||
- webpack-plugin-serve
|
- webpack-plugin-serve
|
||||||
|
|
||||||
|
react-smooth@4.0.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
fast-equals: 5.2.2
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
|
||||||
react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.9
|
'@babel/runtime': 7.26.9
|
||||||
|
@ -11930,6 +12034,23 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
|
recharts-scale@0.4.5:
|
||||||
|
dependencies:
|
||||||
|
decimal.js-light: 2.5.1
|
||||||
|
|
||||||
|
recharts@2.15.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
clsx: 2.1.1
|
||||||
|
eventemitter3: 4.0.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
react-is: 18.3.1
|
||||||
|
react-smooth: 4.0.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
recharts-scale: 0.4.5
|
||||||
|
tiny-invariant: 1.3.3
|
||||||
|
victory-vendor: 36.9.2
|
||||||
|
|
||||||
recursive-readdir@2.2.3:
|
recursive-readdir@2.2.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
minimatch: 3.1.2
|
minimatch: 3.1.2
|
||||||
|
@ -12492,6 +12613,8 @@ snapshots:
|
||||||
|
|
||||||
svg-parser@2.0.4: {}
|
svg-parser@2.0.4: {}
|
||||||
|
|
||||||
|
svg-partial-circle@1.0.0: {}
|
||||||
|
|
||||||
svgo@1.3.2:
|
svgo@1.3.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk: 2.4.2
|
chalk: 2.4.2
|
||||||
|
@ -12601,6 +12724,8 @@ snapshots:
|
||||||
|
|
||||||
thunky@1.1.0: {}
|
thunky@1.1.0: {}
|
||||||
|
|
||||||
|
tiny-invariant@1.3.3: {}
|
||||||
|
|
||||||
tmpl@1.0.5: {}
|
tmpl@1.0.5: {}
|
||||||
|
|
||||||
to-regex-range@5.0.1:
|
to-regex-range@5.0.1:
|
||||||
|
@ -12789,6 +12914,23 @@ snapshots:
|
||||||
|
|
||||||
vary@1.1.2: {}
|
vary@1.1.2: {}
|
||||||
|
|
||||||
|
victory-vendor@36.9.2:
|
||||||
|
dependencies:
|
||||||
|
'@types/d3-array': 3.2.1
|
||||||
|
'@types/d3-ease': 3.0.2
|
||||||
|
'@types/d3-interpolate': 3.0.4
|
||||||
|
'@types/d3-scale': 4.0.9
|
||||||
|
'@types/d3-shape': 3.1.7
|
||||||
|
'@types/d3-time': 3.0.4
|
||||||
|
'@types/d3-timer': 3.0.2
|
||||||
|
d3-array: 3.2.4
|
||||||
|
d3-ease: 3.0.1
|
||||||
|
d3-interpolate: 3.0.1
|
||||||
|
d3-scale: 4.0.2
|
||||||
|
d3-shape: 3.2.0
|
||||||
|
d3-time: 3.1.0
|
||||||
|
d3-timer: 3.0.1
|
||||||
|
|
||||||
w3c-hr-time@1.0.2:
|
w3c-hr-time@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
browser-process-hrtime: 1.0.0
|
browser-process-hrtime: 1.0.0
|
||||||
|
|
27
public/Login.svg
Normal file
After Width: | Height: | Size: 14 MiB |
BIN
public/apple_store.png
Normal file
After Width: | Height: | Size: 5 KiB |
BIN
public/dev-bg.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
public/developer.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
public/google_play.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
public/iMockup - iPhone.png
Normal file
After Width: | Height: | Size: 221 KiB |
|
@ -3,6 +3,11 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Gilroy:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="../src/index.css">
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
|
|
BIN
public/vector-arrows.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
|
@ -219,7 +219,7 @@ export default function AddBookingModal({
|
||||||
{carNames.map((car, index) => (
|
{carNames.map((car, index) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={car.id}
|
key={car.id}
|
||||||
value={car.id}
|
value={car.name}
|
||||||
>
|
>
|
||||||
{car.name}
|
{car.name}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
|
@ -239,7 +239,6 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontSize: "18px",
|
fontSize: "18px",
|
||||||
fontFamily: "Gilroy",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Dynamic title based on the page type */}
|
{/* Dynamic title based on the page type */}
|
||||||
|
@ -419,7 +418,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
key={column.id}
|
key={column.id}
|
||||||
sx={{
|
sx={{
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
fontWeight: "bold",
|
fontWeight: "600",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{column.label}
|
{column.label}
|
||||||
|
@ -440,7 +439,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
<StyledTableCell
|
<StyledTableCell
|
||||||
key={column.id}
|
key={column.id}
|
||||||
sx={{
|
sx={{
|
||||||
color: "#FFFFFF",
|
color: "#D9D8D8",
|
||||||
backgroundColor: "#272727",
|
backgroundColor: "#272727",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { useDispatch } from "react-redux";
|
||||||
import {
|
import {
|
||||||
updateSlot,
|
updateSlot,
|
||||||
fetchAvailableSlots,
|
fetchAvailableSlots,
|
||||||
|
fetchManagersSlots,
|
||||||
} from "../../redux/slices/slotSlice.ts"; // Update with correct action
|
} from "../../redux/slices/slotSlice.ts"; // Update with correct action
|
||||||
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css"; // Custom styled components
|
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css"; // Custom styled components
|
||||||
import { AppDispatch } from "../../redux/store/store.ts";
|
import { AppDispatch } from "../../redux/store/store.ts";
|
||||||
|
@ -86,7 +87,7 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
|
||||||
isAvailable: availabilityStatus,
|
isAvailable: availabilityStatus,
|
||||||
})
|
})
|
||||||
).unwrap();
|
).unwrap();
|
||||||
dispatch(fetchAvailableSlots());
|
dispatch(fetchManagersSlots());
|
||||||
handleClose(); // Close modal on success
|
handleClose(); // Close modal on success
|
||||||
reset(); // Reset form fields after submit
|
reset(); // Reset form fields after submit
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -145,7 +146,6 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
|
||||||
|
|
||||||
{/* Input Fields */}
|
{/* Input Fields */}
|
||||||
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 2 }}>
|
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 2 }}>
|
||||||
|
|
||||||
{/* Start Time */}
|
{/* Start Time */}
|
||||||
<Box sx={{ flex: "1 1 48%" }}>
|
<Box sx={{ flex: "1 1 48%" }}>
|
||||||
<Typography variant="body2" fontWeight={500} mb={0.5}>
|
<Typography variant="body2" fontWeight={500} mb={0.5}>
|
||||||
|
|
|
@ -28,14 +28,13 @@ export default function Header() {
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
// height: "84px",
|
height: "84px",
|
||||||
// backgroundColor: "#1C1C1C",
|
backgroundColor: "#1C1C1C",
|
||||||
padding: { xs: "20px 12px", sm: "20px 24px" },
|
padding: { xs: "20px 12px", sm: "20px 24px" },
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
flexDirection: { xs: "column", sm: "row" },
|
flexDirection: { xs: "column", sm: "row" },
|
||||||
// padding:"0px"
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack
|
<Stack
|
||||||
|
|
|
@ -4,10 +4,14 @@ import Card from "@mui/material/Card";
|
||||||
import CardContent from "@mui/material/CardContent";
|
import CardContent from "@mui/material/CardContent";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import { LineChart } from "@mui/x-charts/LineChart";
|
import { LineChart } from "@mui/x-charts/LineChart";
|
||||||
import { FormControl, MenuItem, Select } from "@mui/material";
|
import TextField from "@mui/material/TextField";
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
import Button from "@mui/material/Button";
|
||||||
|
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { AppDispatch, RootState } from "../../redux/store/store";
|
||||||
|
import { fetchDashboardData } from "../../redux/slices/dashboardSlice";
|
||||||
|
|
||||||
function AreaGradient({ color, id }: { color: string; id: string }) {
|
function AreaGradient({ color, id }: { color: string; id: string }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id={id} x1="50%" y1="0%" x2="50%" y2="100%">
|
<linearGradient id={id} x1="50%" y1="0%" x2="50%" y2="100%">
|
||||||
|
@ -18,148 +22,173 @@ function AreaGradient({ color, id }: { color: string; id: string }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDaysInMonth(month: number, year: number) {
|
|
||||||
const date = new Date(year, month, 0);
|
|
||||||
const monthName = date.toLocaleDateString("en-US", {
|
|
||||||
month: "short",
|
|
||||||
});
|
|
||||||
const daysInMonth = date.getDate();
|
|
||||||
const days = [];
|
|
||||||
let i = 1;
|
|
||||||
while (days.length < daysInMonth) {
|
|
||||||
days.push(`${monthName} ${i}`);
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
return days;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function LineChartCard() {
|
export default function LineChartCard() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const data = getDaysInMonth(4, 2024);
|
const isXsScreen = useMediaQuery(theme.breakpoints.down("sm"));
|
||||||
|
const isSmScreen = useMediaQuery(theme.breakpoints.between("sm", "md"));
|
||||||
|
|
||||||
const colorPalette = [theme.palette.primary.light];
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
const [selectedOption, setSelectedOption] = React.useState("Weekly");
|
const { totalBookings, loading } = useSelector(
|
||||||
|
(state: RootState) => state.dashboardReducer
|
||||||
const handleChange = (event: { target: { value: React.SetStateAction<string>; }; }) => {
|
);
|
||||||
setSelectedOption(event.target.value);
|
|
||||||
};
|
// States for date range inputs
|
||||||
|
const [startDateBookings, setStartDateBookings] = React.useState("");
|
||||||
|
const [endDateBookings, setEndDateBookings] = React.useState("");
|
||||||
|
|
||||||
|
// Function to fetch data with date filters
|
||||||
|
const handleFetchData = () => {
|
||||||
|
dispatch(fetchDashboardData({ startDateBookings, endDateBookings }));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate chart data points (simulated here)
|
||||||
|
const totalPoints = 10; // Divide total bookings into 10 intervals
|
||||||
|
const chartData = Array.from({ length: totalPoints }, (_, i) => ({
|
||||||
|
label: `Day ${i + 1}`,
|
||||||
|
value: Math.round((totalBookings / totalPoints) * (i + 1)),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Calculate responsive chart dimensions
|
||||||
|
const getChartHeight = () => (isXsScreen ? 200 : isSmScreen ? 220 : 250);
|
||||||
|
const getChartMargin = () =>
|
||||||
|
isXsScreen
|
||||||
|
? { left: 35, right: 10, top: 15, bottom: 15 }
|
||||||
|
: isSmScreen
|
||||||
|
? { left: 40, right: 15, top: 18, bottom: 18 }
|
||||||
|
: { left: 50, right: 20, top: 20 };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{
|
sx={{
|
||||||
width: "553px",
|
width: "100%",
|
||||||
height: "444px",
|
height: "auto",
|
||||||
|
minHeight: { xs: "360px", sm: "400px", md: "444px" },
|
||||||
borderRadius: "16px",
|
borderRadius: "16px",
|
||||||
|
border: "none",
|
||||||
"*:where([data-mui-color-scheme='dark']) &": {
|
"*:where([data-mui-color-scheme='dark']) &": {
|
||||||
backgroundColor: "#202020",
|
backgroundColor: "#202020",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardContent>
|
<CardContent
|
||||||
|
sx={{
|
||||||
|
padding: { xs: 2, md: 3 },
|
||||||
|
"&:last-child": { paddingBottom: { xs: 2, md: 3 } },
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
|
flexDirection: isXsScreen ? "column" : "row",
|
||||||
color: "#F2F2F2",
|
color: "#F2F2F2",
|
||||||
|
marginBottom: isXsScreen ? 16 : 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h6"
|
variant="h6"
|
||||||
align="left"
|
align={isXsScreen ? "center" : "left"}
|
||||||
color="#F2F2F2"
|
color="#F2F2F2"
|
||||||
sx={{
|
sx={{
|
||||||
fontFamily: "Gilroy",
|
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontSize: "18px",
|
fontSize: { xs: "16px", sm: "17px", md: "18px" },
|
||||||
lineHeight: "24px",
|
lineHeight: "24px",
|
||||||
|
marginBottom: isXsScreen ? 2 : 0,
|
||||||
|
width: isXsScreen ? "100%" : "auto",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Sales Stats
|
Total Bookings Stats
|
||||||
</Typography>
|
</Typography>
|
||||||
<FormControl
|
|
||||||
sx={{
|
|
||||||
mt: 2,
|
|
||||||
mb: 2,
|
|
||||||
backgroundColor: "#202020",
|
|
||||||
marginLeft: "auto",
|
|
||||||
marginRight: "16px",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
// p: 1.5,
|
|
||||||
color: "#F2F2F2",
|
|
||||||
width: "149px",
|
|
||||||
height: "44px",
|
|
||||||
padding: "12px 16px",
|
|
||||||
gap: "8px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
value={selectedOption}
|
|
||||||
onChange={handleChange}
|
|
||||||
sx={{
|
|
||||||
//backgroundColor: "#202020",
|
|
||||||
color: "#D9D8D8",
|
|
||||||
".MuiSelect-icon": {
|
|
||||||
color: "#F2F2F2", // Icon color
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
IconComponent={ExpandMoreIcon}
|
|
||||||
>
|
|
||||||
<MenuItem value="Monthly">Monthly</MenuItem>
|
|
||||||
<MenuItem value="Weekly">Weekly</MenuItem>
|
|
||||||
<MenuItem value="Daily">Daily</MenuItem>
|
|
||||||
<MenuItem value="Yearly">Yearly</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Input fields for start and end date */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: isXsScreen ? "column" : "row",
|
||||||
|
gap: "16px",
|
||||||
|
marginTop: "16px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
type="date"
|
||||||
|
label="Start Date"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
value={startDateBookings}
|
||||||
|
onChange={(e) => setStartDateBookings(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#202020",
|
||||||
|
borderRadius: "8px",
|
||||||
|
"& .MuiInputBase-input": {
|
||||||
|
color: "#F2F2F2",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
type="date"
|
||||||
|
label="End Date"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
value={endDateBookings}
|
||||||
|
onChange={(e) => setEndDateBookings(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#202020",
|
||||||
|
borderRadius: "8px",
|
||||||
|
"& .MuiInputBase-input": {
|
||||||
|
color: "#F2F2F2",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={handleFetchData}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#52ACDF",
|
||||||
|
color: "white",
|
||||||
|
borderRadius: "8px",
|
||||||
|
padding: "10px 20px",
|
||||||
|
|
||||||
|
"&:hover": { backgroundColor: "#3A94C0" },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Fetch
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Line Chart */}
|
||||||
<LineChart
|
<LineChart
|
||||||
colors={colorPalette}
|
colors={[theme.palette.primary.main]}
|
||||||
xAxis={[
|
xAxis={[
|
||||||
{
|
{
|
||||||
scaleType: "point",
|
scaleType: "point",
|
||||||
data,
|
data: chartData.map((data) => data.label), // Use intervals as x-axis labels
|
||||||
tickInterval: (index, i) => (i + 1) % 5 === 0,
|
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
series={[
|
series={[
|
||||||
{
|
{
|
||||||
id: "direct",
|
id: "totalBookings",
|
||||||
label: "Direct",
|
|
||||||
showMark: false,
|
showMark: false,
|
||||||
curve: "linear",
|
curve: "linear",
|
||||||
stack: "total",
|
|
||||||
area: true,
|
area: true,
|
||||||
stackOrder: "ascending",
|
data: chartData.map((data) => data.value), // Use interval data for y-axis
|
||||||
data: [
|
color: theme.palette.primary.main,
|
||||||
300, 900, 500, 1200, 1500, 1800, 2400, 2100,
|
|
||||||
2700, 3000, 1800, 3300, 3600, 3900, 4200, 4500,
|
|
||||||
3900, 4800, 5100, 5400, 4500, 5700, 6000, 6300,
|
|
||||||
6600, 6900, 7200, 7500, 7800, 8100,
|
|
||||||
],
|
|
||||||
color: "#FFFFFF",
|
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
height={250}
|
height={getChartHeight()}
|
||||||
margin={{ left: 50, right: 20, top: 20, bottom: 20 }}
|
margin={getChartMargin()}
|
||||||
grid={{ horizontal: true }}
|
grid={{ horizontal: true }}
|
||||||
sx={{
|
sx={{
|
||||||
"& .MuiAreaElement-series-direct": {
|
"& .MuiAreaElement-series-totalBookings": {
|
||||||
fill: "url('#direct')",
|
fill: "url('#totalBookings')",
|
||||||
},
|
|
||||||
}}
|
|
||||||
slotProps={{
|
|
||||||
legend: {
|
|
||||||
hidden: true,
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AreaGradient
|
<AreaGradient
|
||||||
color={theme.palette.primary.light}
|
color={theme.palette.primary.main}
|
||||||
id="direct"
|
id="totalBookings"
|
||||||
/>
|
/>
|
||||||
</LineChart>
|
</LineChart>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
|
import Grid from "@mui/material/Grid";
|
||||||
import Grid from "@mui/material/Grid2";
|
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import SessionsChart from "../SessionsChart/sessionChart";
|
import SessionsChart from "../SessionsChart/sessionChart";
|
||||||
|
@ -7,59 +6,85 @@ import StatCard, { StatCardProps } from "../StatCard/statCard";
|
||||||
import ResourcesPieChart from "../ResourcePieChart/resourcePieChart";
|
import ResourcesPieChart from "../ResourcePieChart/resourcePieChart";
|
||||||
import RoundedBarChart from "../barChartCard/barChartCard";
|
import RoundedBarChart from "../barChartCard/barChartCard";
|
||||||
import LineChartCard from "../LineChartCard/lineChartCard";
|
import LineChartCard from "../LineChartCard/lineChartCard";
|
||||||
|
import { AppDispatch, RootState } from "../../redux/store/store";
|
||||||
const data: StatCardProps[] = [
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
{
|
import { fetchDashboardData } from "../../redux/slices/dashboardSlice";
|
||||||
title: "Total Charge Stations",
|
import { useEffect } from "react";
|
||||||
value: "86",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Charging Completed",
|
|
||||||
value: "12",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Active Users",
|
|
||||||
value: "24",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Total Energy Consumed",
|
|
||||||
value: "08",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function MainGrid() {
|
export default function MainGrid() {
|
||||||
return (
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
<Box sx={{ width: "100%", maxWidth: { sm: "100%", md: "1700px" } }}>
|
const {
|
||||||
{/* cards */}
|
totalAdmins,
|
||||||
|
totalManagers,
|
||||||
|
totalUsers,
|
||||||
|
totalStations,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
} = useSelector((state: RootState) => state.dashboardReducer);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const staticData = {
|
||||||
|
totalAdmins: 86,
|
||||||
|
totalManagers: 12,
|
||||||
|
totalUsers: 24,
|
||||||
|
totalStations: 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
dispatch(fetchDashboardData());
|
||||||
|
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
const data =
|
||||||
|
{ totalAdmins, totalManagers, totalUsers, totalStations }
|
||||||
|
|
||||||
|
|
||||||
|
const statCards = [
|
||||||
|
{ title: "Total Admins", value: data.totalAdmins },
|
||||||
|
{ title: "Total Managers", value: data.totalManagers },
|
||||||
|
{ title: "Total Users", value: data.totalUsers },
|
||||||
|
{ title: "Total Stations", value: data.totalStations },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: "1600px",
|
||||||
|
mx: "auto",
|
||||||
|
px: { xs: 2, sm: 1, md: 0 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Dashboard Header */}
|
||||||
<Typography component="h2" variant="h6" sx={{ mb: 2 }}>
|
<Typography component="h2" variant="h6" sx={{ mb: 2 }}>
|
||||||
Dashboard
|
Dashboard
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid
|
|
||||||
container
|
{/* Grid Layout */}
|
||||||
spacing={3}
|
<Grid container spacing={3} columns={12}>
|
||||||
columns={12}
|
{/* Statistic Cards */}
|
||||||
|
{statCards.map((card, index) => (
|
||||||
// sx={{ mb: (theme) => theme.spacing(2) }}
|
<Grid key={index} item xs={12} sm={6} md={3} lg={3}>
|
||||||
>
|
|
||||||
{data.map((card, index) => (
|
|
||||||
<Grid key={index} size={{ xs: 12, sm: 6, lg: 3 }}>
|
|
||||||
<StatCard {...card} />
|
<StatCard {...card} />
|
||||||
</Grid>
|
</Grid>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<Grid size={{ xs: 12, md: 6 }}>
|
{/* Charts */}
|
||||||
|
<Grid item xs={12} sm={12} md={6} lg={6}>
|
||||||
<SessionsChart />
|
<SessionsChart />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid size={{ xs: 12, md: 6 }}>
|
<Grid item xs={12} sm={12} md={6} lg={6}>
|
||||||
<ResourcesPieChart />
|
<ResourcesPieChart />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid size={{ xs: 12, md: 6 }}>
|
<Grid item xs={12} sm={12} md={6} lg={6}>
|
||||||
<RoundedBarChart />
|
<RoundedBarChart />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid size={{ xs: 12, md: 6 }}>
|
<Grid item xs={12} sm={12} md={6} lg={6}>
|
||||||
<LineChartCard />
|
<LineChartCard />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,12 +37,12 @@ export default function MenuContent({ hidden }: PropType) {
|
||||||
},
|
},
|
||||||
userRole === "superadmin" && {
|
userRole === "superadmin" && {
|
||||||
text: "Manager",
|
text: "Manager",
|
||||||
icon: <ManageAccountsOutlinedIcon />,
|
icon: <PeopleOutlinedIcon />,
|
||||||
url: "/panel/all-managers-list",
|
url: "/panel/all-managers-list",
|
||||||
},
|
},
|
||||||
userRole === "superadmin" && {
|
userRole === "superadmin" && {
|
||||||
text: "User",
|
text: "User",
|
||||||
icon: <ManageAccountsOutlinedIcon />,
|
icon: <PeopleOutlinedIcon />,
|
||||||
url: "/panel/user-list",
|
url: "/panel/user-list",
|
||||||
},
|
},
|
||||||
userRole === "superadmin" && {
|
userRole === "superadmin" && {
|
||||||
|
|
|
@ -4,84 +4,173 @@ import Card from "@mui/material/Card";
|
||||||
import CardContent from "@mui/material/CardContent";
|
import CardContent from "@mui/material/CardContent";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Stack from "@mui/material/Stack";
|
import Stack from "@mui/material/Stack";
|
||||||
|
import { useTheme } from "@mui/material/styles";
|
||||||
|
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||||
|
import { AppDispatch, RootState } from "../../redux/store/store";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { fetchDashboardData } from "../../redux/slices/dashboardSlice";
|
||||||
|
|
||||||
const colorPalette = [
|
const colorPalette = [
|
||||||
"hsla(202, 69%, 60%, 1)",
|
"hsla(202, 69%, 60%, 1)",
|
||||||
"hsl(204, 48.60%, 72.50%)",
|
"hsl(204, 48.60%, 72.50%)",
|
||||||
"hsl(214, 56.40%, 30.60%)",
|
"hsl(214, 56.40%, 30.60%)",
|
||||||
"hsl(222, 6.80%, 50.80%)",
|
"hsl(222, 6.80%, 50.80%)",
|
||||||
];
|
|
||||||
const data = [
|
|
||||||
{ title: "Total Resources", value: 50, color: colorPalette[0] },
|
|
||||||
{ title: "Total Stations", value: 20, color: colorPalette[1] },
|
|
||||||
{ title: "Station Manager", value: 15, color: colorPalette[2] },
|
|
||||||
{ title: "Total Booth", value: 15, color: colorPalette[3] },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// const data = [
|
||||||
|
// { title: "Total Resources", value: 50, color: colorPalette[0] },
|
||||||
|
// { title: "Total Stations", value: 20, color: colorPalette[1] },
|
||||||
|
// { title: "Station Manager", value: 15, color: colorPalette[2] },
|
||||||
|
// { title: "Total Booth", value: 15, color: colorPalette[3] },
|
||||||
|
// ];
|
||||||
|
|
||||||
export default function ResourcePieChart() {
|
export default function ResourcePieChart() {
|
||||||
return (
|
const theme = useTheme();
|
||||||
|
const isXsScreen = useMediaQuery(theme.breakpoints.down("sm"));
|
||||||
|
const isSmScreen = useMediaQuery(theme.breakpoints.between("sm", "md"));
|
||||||
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
|
|
||||||
|
// // Fetch role and carPortCounts from Redux state
|
||||||
|
// const {user} = useSelector((state: RootState) => state.profileReducer); // Assuming user role is stored in Redux
|
||||||
|
const { carPortCounts } = useSelector(
|
||||||
|
(state: RootState) => state.dashboardReducer
|
||||||
|
);
|
||||||
|
console.log("first",carPortCounts)
|
||||||
|
// Static data for non-superadmin roles
|
||||||
|
// const staticCarPorts = [
|
||||||
|
// { carPort: "240V", count: 5 },
|
||||||
|
// { carPort: "120V", count: 3 },
|
||||||
|
// { carPort: "DCFC", count: 2 },
|
||||||
|
// { carPort: "Other", count: 7 },
|
||||||
|
// ];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
dispatch(fetchDashboardData());
|
||||||
|
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
// console.log("Raw CarPortCounts from API:", carPortCounts);
|
||||||
|
|
||||||
|
const dataToDisplay =carPortCounts
|
||||||
|
|
||||||
|
// const dataToDisplay =
|
||||||
|
// user?.userType === "superadmin"
|
||||||
|
// ? carPortCounts.filter((entry) => entry.count > 0) // Exclude zero counts
|
||||||
|
// : staticCarPorts.filter((entry) => entry.count > 0);
|
||||||
|
// console.log("Filtered Data to Display:", dataToDisplay);
|
||||||
|
const getChartDimensions = () => {
|
||||||
|
if (isXsScreen) {
|
||||||
|
return {
|
||||||
|
height: 240,
|
||||||
|
width: 240,
|
||||||
|
innerRadius: 40,
|
||||||
|
outerRadius: 80,
|
||||||
|
margin: { left: 20, right: 20, top: 40, bottom: 40 }
|
||||||
|
};
|
||||||
|
} else if (isSmScreen) {
|
||||||
|
return {
|
||||||
|
height: 260,
|
||||||
|
width: 260,
|
||||||
|
innerRadius: 50,
|
||||||
|
outerRadius: 90,
|
||||||
|
margin: { left: 40, right: 40, top: 60, bottom: 60 }
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
height: 350,
|
||||||
|
width: 350,
|
||||||
|
innerRadius: 55,
|
||||||
|
outerRadius: 110,
|
||||||
|
margin: { left: 60, right: 80, top: 80, bottom: 80 }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const dimensions = getChartDimensions();
|
||||||
|
|
||||||
|
return (
|
||||||
<Card
|
<Card
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
gap: "12px",
|
gap: { xs: "8px", sm: "10px", md: "12px" },
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
width: "553px",
|
width: "100%",
|
||||||
height: "324px",
|
height: "auto",
|
||||||
padding: "16px",
|
minHeight: { xs: "320px", sm: "340px", md: "360px" },
|
||||||
|
padding: { xs: "12px", sm: "14px", md: "16px" },
|
||||||
borderRadius: "16px",
|
borderRadius: "16px",
|
||||||
|
border: "none",
|
||||||
"*:where([data-mui-color-scheme='dark']) &": {
|
"*:where([data-mui-color-scheme='dark']) &": {
|
||||||
backgroundColor: "#202020",
|
backgroundColor: "#202020",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardContent>
|
<CardContent
|
||||||
|
sx={{ padding: 0, "&:last-child": { paddingBottom: 0 } }}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
component="h2"
|
component="h2"
|
||||||
variant="subtitle2"
|
variant="subtitle2"
|
||||||
color="#F2F2F2"
|
color="#F2F2F2"
|
||||||
width="84px"
|
|
||||||
height="24px"
|
|
||||||
sx={{
|
sx={{
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontSize: "18px",
|
fontSize: { xs: "16px", sm: "17px", md: "18px" },
|
||||||
lineHeight: "24px",
|
lineHeight: "24px",
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
|
marginBottom: { xs: 1, sm: 1.5, md: 2 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Resources
|
Car Port Usage
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: { xs: "column", sm: "row" },
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<PieChart
|
<PieChart
|
||||||
colors={colorPalette}
|
colors={colorPalette}
|
||||||
margin={{
|
margin={dimensions.margin}
|
||||||
left: 60,
|
|
||||||
right: 80,
|
|
||||||
top: 80,
|
|
||||||
bottom: 80,
|
|
||||||
}}
|
|
||||||
series={[
|
series={[
|
||||||
{
|
{
|
||||||
data,
|
data: dataToDisplay.map((entry, index) => ({
|
||||||
innerRadius: 50,
|
title: entry.carPort,
|
||||||
outerRadius: 100,
|
value: entry.count,
|
||||||
paddingAngle: 0,
|
color: colorPalette[
|
||||||
|
index % colorPalette.length
|
||||||
|
],
|
||||||
|
})),
|
||||||
|
innerRadius: dimensions.innerRadius,
|
||||||
|
outerRadius: dimensions.outerRadius,
|
||||||
|
paddingAngle: 2,
|
||||||
|
cornerRadius: 8,
|
||||||
highlightScope: {
|
highlightScope: {
|
||||||
faded: "global",
|
faded: "global",
|
||||||
highlighted: "item",
|
highlighted: "item",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
height={300}
|
height={dimensions.height}
|
||||||
width={300}
|
width={dimensions.width}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
legend: { hidden: true },
|
legend: { hidden: true },
|
||||||
}}
|
}}
|
||||||
></PieChart>
|
/>
|
||||||
|
|
||||||
<Stack spacing={1}>
|
<Stack
|
||||||
{data.map((entry, index) => (
|
spacing={1}
|
||||||
|
sx={{
|
||||||
|
mt: { xs: 2, sm: 0 },
|
||||||
|
ml: { xs: 0, sm: 2 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{dataToDisplay.map((entry, index) => (
|
||||||
<Stack
|
<Stack
|
||||||
key={index}
|
key={index}
|
||||||
direction="row"
|
direction="row"
|
||||||
|
@ -90,19 +179,27 @@ export default function ResourcePieChart() {
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: 16,
|
width: { xs: 12, sm: 14, md: 16 },
|
||||||
height: 16,
|
height: { xs: 12, sm: 14, md: 16 },
|
||||||
backgroundColor: entry.color,
|
backgroundColor:
|
||||||
|
colorPalette[
|
||||||
|
index % colorPalette.length
|
||||||
|
],
|
||||||
borderRadius: "50%",
|
borderRadius: "50%",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Typography
|
<Typography
|
||||||
variant="body2"
|
variant="body2"
|
||||||
width="100px"
|
sx={{
|
||||||
height="16px"
|
fontSize: {
|
||||||
color="#FFFFFF"
|
xs: "12px",
|
||||||
|
sm: "13px",
|
||||||
|
md: "14px",
|
||||||
|
},
|
||||||
|
color: "#FFFFFF",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{entry.title}
|
{entry.carPort}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
))}
|
))}
|
||||||
|
@ -110,5 +207,5 @@ export default function ResourcePieChart() {
|
||||||
</Box>
|
</Box>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -6,156 +6,146 @@ import Box from "@mui/material/Box";
|
||||||
import Select from "@mui/material/Select";
|
import Select from "@mui/material/Select";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import FormControl from "@mui/material/FormControl";
|
import FormControl from "@mui/material/FormControl";
|
||||||
import InputLabel from "@mui/material/InputLabel";
|
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
import { useTheme } from "@mui/material/styles";
|
||||||
|
|
||||||
export default function SessionsChart() {
|
export default function SessionsChart() {
|
||||||
const [selectedStation, setSelectedStation] = React.useState(
|
const theme = useTheme();
|
||||||
"Delhi NCR EV Station"
|
const [selectedStation, setSelectedStation] = React.useState(
|
||||||
);
|
"Delhi NCR EV Station"
|
||||||
|
);
|
||||||
|
|
||||||
const handleChange = (event: { target: { value: React.SetStateAction<string>; }; }) => {
|
const handleChange = (event: { target: { value: React.SetStateAction<string> } }) => {
|
||||||
setSelectedStation(event.target.value);
|
setSelectedStation(event.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{
|
sx={{
|
||||||
width: "553px",
|
width: "100%",
|
||||||
height: "324px",
|
height: "auto",
|
||||||
gap: "16px",
|
minHeight: { xs: "260px", sm: "270px", md: "290px" },
|
||||||
borderRadius: "16px",
|
gap: "16px",
|
||||||
padding: "20px",
|
borderRadius: "16px",
|
||||||
"*:where([data-mui-color-scheme='dark']) &": {
|
padding: { xs: "12px", sm: "16px", md: "20px" },
|
||||||
backgroundColor: "#202020",
|
border: "none",
|
||||||
},
|
"*:where([data-mui-color-scheme='dark']) &": {
|
||||||
}}
|
backgroundColor: "#202020",
|
||||||
>
|
},
|
||||||
<CardContent>
|
}}
|
||||||
<Typography
|
>
|
||||||
variant="h6"
|
<CardContent sx={{ padding: 0, "&:last-child": { paddingBottom: 0 } }}>
|
||||||
align="left"
|
<Typography
|
||||||
color="#F2F2F2"
|
variant="h6"
|
||||||
width="132px"
|
align="left"
|
||||||
height="24px"
|
color="#F2F2F2"
|
||||||
gap={"12px"}
|
sx={{
|
||||||
sx={{
|
fontWeight: 500,
|
||||||
fontFamily: "Gilroy",
|
fontSize: { xs: "16px", sm: "17px", md: "18px" },
|
||||||
fontWeight: 500,
|
lineHeight: "24px",
|
||||||
fontSize: "18px",
|
letterSpacing: "0%",
|
||||||
lineHeight: "24px",
|
color: "#FAFAFA",
|
||||||
letterSpacing: "0%",
|
marginBottom: { xs: 1, sm: 1.5, md: 2 },
|
||||||
color: "#FAFAFA",
|
}}
|
||||||
}}
|
>
|
||||||
>
|
Charging prices
|
||||||
Charging prices
|
</Typography>
|
||||||
</Typography>
|
|
||||||
|
|
||||||
{/* Dropdown button */}
|
{/* Dropdown button */}
|
||||||
<FormControl
|
<FormControl
|
||||||
sx={{
|
sx={{
|
||||||
mt: 2,
|
mt: { xs: 1, sm: 1.5, md: 2 },
|
||||||
mb: 2,
|
mb: { xs: 1, sm: 1.5, md: 2 },
|
||||||
width: "100%",
|
width: "100%",
|
||||||
// backgroundColor: "#202020",
|
border: "none",
|
||||||
border: "1px solid #454545",
|
borderRadius: "8px",
|
||||||
borderRadius: "8px",
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<Select
|
||||||
|
value={selectedStation}
|
||||||
<Select
|
onChange={handleChange}
|
||||||
value={selectedStation}
|
label="Select Station"
|
||||||
onChange={handleChange}
|
sx={{
|
||||||
label="Select Station"
|
color: "#D9D8D8",
|
||||||
sx={{
|
"& .MuiSvgIcon-root": { color: "#F2F2F2" },
|
||||||
//backgroundColor: "#202020",
|
fontSize: { xs: "14px", md: "16px" },
|
||||||
color: "#D9D8D8",
|
}}
|
||||||
"& .MuiSvgIcon-root": { color: "#F2F2F2" },
|
IconComponent={ExpandMoreIcon}
|
||||||
}}
|
>
|
||||||
IconComponent={ExpandMoreIcon}
|
<MenuItem value="Delhi NCR EV Station">Delhi NCR EV Station</MenuItem>
|
||||||
>
|
<MenuItem value="Mumbai EV Station">Mumbai EV Station</MenuItem>
|
||||||
<MenuItem value="Delhi NCR EV Station">
|
<MenuItem value="Bangalore EV Station">Bangalore EV Station</MenuItem>
|
||||||
Delhi NCR EV Station
|
<MenuItem value="Pune EV Station">Pune EV Station</MenuItem>
|
||||||
</MenuItem>
|
</Select>
|
||||||
<MenuItem value="Mumbai EV Station">
|
</FormControl>
|
||||||
Mumbai EV Station
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value="Bangalore EV Station">
|
|
||||||
Bangalore EV Station
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value="Pune EV Station">
|
|
||||||
Pune EV Station
|
|
||||||
</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
{/* Grid container for the four boxes */}
|
{/* Grid container for the four boxes */}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridTemplateColumns: {
|
gridTemplateColumns: {
|
||||||
xs: "1fr",
|
xs: "repeat(1, 1fr)", // 1 column on mobile
|
||||||
sm: "repeat(2, 1fr)",
|
sm: "repeat(2, 1fr)", // 2 columns on tablets
|
||||||
},
|
md: "repeat(2, 1fr)", // 2x2 grid on desktop
|
||||||
gap: { xs: 1, sm: 2 },
|
},
|
||||||
maxWidth: "750px",
|
gap: { xs: 1, sm: 1.5, md: 2 },
|
||||||
width: "100%",
|
width: "100%",
|
||||||
mx: "auto",
|
}}
|
||||||
}}
|
>
|
||||||
>
|
{[1, 2, 3, 4].map((item) => (
|
||||||
{[1, 2, 3, 4].map((item) => (
|
<Box
|
||||||
<Box
|
key={item}
|
||||||
key={item}
|
sx={{
|
||||||
sx={{
|
height: { xs: "105px", sm: "115px", md: "128px" },
|
||||||
height: "84px",
|
borderRadius: "8px",
|
||||||
borderRadius: "8px",
|
p: { xs: "10px", sm: "12px", md: "14px" },
|
||||||
p: "12px 16px",
|
backgroundColor: "#272727",
|
||||||
backgroundColor: "#272727",
|
color: "#D9D8D8",
|
||||||
color: "#D9D8D8",
|
display: "flex",
|
||||||
}}
|
flexDirection: "column",
|
||||||
>
|
justifyContent: "center",
|
||||||
<Typography
|
}}
|
||||||
component="h1"
|
>
|
||||||
variant="body2"
|
<Typography
|
||||||
width="98px"
|
variant="body2"
|
||||||
height="24px"
|
sx={{
|
||||||
fontWeight={400}
|
fontWeight: 400,
|
||||||
fontSize={"14px"}
|
fontSize: { xs: "12px", sm: "13px", md: "14px" },
|
||||||
lineHeight={"24px"}
|
lineHeight: { xs: "20px", md: "24px" },
|
||||||
gutterBottom
|
marginBottom: "4px",
|
||||||
>
|
}}
|
||||||
Basic Charging
|
gutterBottom
|
||||||
</Typography>
|
>
|
||||||
<Box display={"flex"} gap={1}>
|
Basic Charging
|
||||||
<Typography
|
</Typography>
|
||||||
component="h1"
|
<Box display="flex" gap={1} alignItems="center">
|
||||||
variant="subtitle2"
|
<Typography
|
||||||
color="#FFFFFF"
|
variant="subtitle2"
|
||||||
width="40px"
|
color="#FFFFFF"
|
||||||
height={"24px"}
|
sx={{
|
||||||
fontWeight={500}
|
fontWeight: 500,
|
||||||
fontSize="18px"
|
fontSize: { xs: "16px", sm: "17px", md: "18px" },
|
||||||
lineHeight="24px"
|
lineHeight: { xs: "20px", md: "24px" },
|
||||||
gutterBottom
|
}}
|
||||||
>
|
gutterBottom
|
||||||
16.83
|
>
|
||||||
</Typography>
|
16.83
|
||||||
|
</Typography>
|
||||||
<Typography
|
<Typography
|
||||||
width="71px"
|
sx={{
|
||||||
height="24px"
|
fontWeight: 400,
|
||||||
gap="2px"
|
fontSize: { xs: "12px", sm: "13px", md: "14px" },
|
||||||
fontWeight={400}
|
lineHeight: { xs: "20px", md: "24px" },
|
||||||
fontSize={"14px"}
|
}}
|
||||||
lineHeight={"24px"}
|
>
|
||||||
>
|
cents/kWh
|
||||||
cents/kWh
|
</Typography>
|
||||||
</Typography>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
))}
|
||||||
))}
|
</Box>
|
||||||
</Box>
|
</CardContent>
|
||||||
</CardContent>
|
</Card>
|
||||||
</Card>
|
);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,59 +1,106 @@
|
||||||
|
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import CardContent from "@mui/material/CardContent";
|
import CardContent from "@mui/material/CardContent";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
|
import { useTheme } from "@mui/material/styles";
|
||||||
|
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||||
|
|
||||||
export type StatCardProps = {
|
export type StatCardProps = {
|
||||||
title: string;
|
title: string;
|
||||||
value: string;
|
value: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function StatCard({ title, value }: StatCardProps) {
|
export default function StatCard({ title, value }: StatCardProps) {
|
||||||
return (
|
const theme = useTheme();
|
||||||
<Card
|
const isXsScreen = useMediaQuery(theme.breakpoints.only("xs"));
|
||||||
variant="outlined"
|
const isSmScreen = useMediaQuery(theme.breakpoints.only("sm"));
|
||||||
sx={{
|
const isMdScreen = useMediaQuery(theme.breakpoints.only("md"));
|
||||||
width: "264.5px",
|
|
||||||
height: "90px",
|
return (
|
||||||
padding: "16px",
|
<Card
|
||||||
borderRadius: "12px",
|
variant="outlined"
|
||||||
gap: "24px",
|
sx={{
|
||||||
"*:where([data-mui-color-scheme='dark']) &": {
|
width: "100%",
|
||||||
backgroundColor: "#202020",
|
height: "100px",
|
||||||
},
|
padding: {
|
||||||
}}
|
xs: "12px",
|
||||||
>
|
sm: "14px",
|
||||||
<CardContent>
|
md: "10px"
|
||||||
<Typography
|
},
|
||||||
component="h2"
|
borderRadius: "12px",
|
||||||
variant="subtitle2"
|
border: "none",
|
||||||
color="#F2F2F2"
|
gap: "24px",
|
||||||
width={"118px"}
|
"*:where([data-mui-color-scheme='dark']) &": {
|
||||||
height={"14px"}
|
backgroundColor: "#202020",
|
||||||
fontWeight={400}
|
},
|
||||||
fontSize={"12px"}
|
}}
|
||||||
lineHeight={"14px"}
|
>
|
||||||
letterSpacing={"0%"}
|
<CardContent
|
||||||
gutterBottom
|
sx={{
|
||||||
>
|
padding: {
|
||||||
{title}
|
xs: "8px",
|
||||||
</Typography>
|
sm: "12px",
|
||||||
<Typography
|
md: "16px"
|
||||||
component="h1"
|
},
|
||||||
variant="body1"
|
"&:last-child": {
|
||||||
color="#F2F2F2"
|
paddingBottom: {
|
||||||
width={"36px"}
|
xs: "8px",
|
||||||
height={"36px"}
|
sm: "12px",
|
||||||
fontSize={"32px"}
|
md: "16px"
|
||||||
fontWeight={600}
|
}
|
||||||
lineHeight={"36px"}
|
}
|
||||||
letterSpacing={"0%"}
|
}}
|
||||||
gutterBottom
|
>
|
||||||
>
|
<Typography
|
||||||
{value}
|
component="h2"
|
||||||
</Typography>
|
variant="subtitle2"
|
||||||
</CardContent>
|
color="#F2F2F2"
|
||||||
</Card>
|
sx={{
|
||||||
);
|
fontWeight: 400,
|
||||||
}
|
fontSize: {
|
||||||
|
xs: "10px",
|
||||||
|
sm: "11px",
|
||||||
|
md: "12px"
|
||||||
|
},
|
||||||
|
lineHeight: {
|
||||||
|
xs: "12px",
|
||||||
|
sm: "13px",
|
||||||
|
md: "14px"
|
||||||
|
},
|
||||||
|
letterSpacing: "0%",
|
||||||
|
width: "auto",
|
||||||
|
height: "auto",
|
||||||
|
marginBottom: { xs: "6px", sm: "8px", md: "10px" }, // Added more spacing
|
||||||
|
|
||||||
|
}}
|
||||||
|
gutterBottom
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
component="h1"
|
||||||
|
variant="body1"
|
||||||
|
color="#D9D8D8"
|
||||||
|
sx={{
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: {
|
||||||
|
xs: "24px",
|
||||||
|
sm: "28px",
|
||||||
|
md: "32px"
|
||||||
|
},
|
||||||
|
lineHeight: {
|
||||||
|
xs: "28px",
|
||||||
|
sm: "32px",
|
||||||
|
md: "36px"
|
||||||
|
},
|
||||||
|
letterSpacing: "0%",
|
||||||
|
width: "auto",
|
||||||
|
height: "auto",
|
||||||
|
}}
|
||||||
|
gutterBottom
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
|
@ -5,125 +5,215 @@ import {
|
||||||
CardContent,
|
CardContent,
|
||||||
Typography,
|
Typography,
|
||||||
Box,
|
Box,
|
||||||
Select,
|
TextField,
|
||||||
MenuItem,
|
Button,
|
||||||
FormControl,
|
|
||||||
SelectChangeEvent,
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { BarChart } from "@mui/x-charts/BarChart";
|
import { BarChart } from "@mui/x-charts/BarChart";
|
||||||
import { axisClasses } from "@mui/x-charts/ChartsAxis";
|
import { axisClasses } from "@mui/x-charts/ChartsAxis";
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||||
|
import { AppDispatch, RootState } from "../../redux/store/store";
|
||||||
// Sample Data
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
const data = [
|
import { fetchDashboardData } from "../../redux/slices/dashboardSlice";
|
||||||
{ name: "Jan", v1: 40 },
|
|
||||||
{ name: "Feb", v1: 50 },
|
|
||||||
{ name: "Mar", v1: 80 },
|
|
||||||
{ name: "Apr", v1: 20 },
|
|
||||||
{ name: "May", v1: 60 },
|
|
||||||
{ name: "Jun", v1: 30 },
|
|
||||||
];
|
|
||||||
|
|
||||||
// Chart Configuration
|
|
||||||
const chartSetting = {
|
|
||||||
yAxis: [
|
|
||||||
{
|
|
||||||
label: "Value",
|
|
||||||
tickFormatter: (value: number) => `${value}`, // Formatting Y-axis ticks
|
|
||||||
},
|
|
||||||
],
|
|
||||||
xAxis: [
|
|
||||||
{
|
|
||||||
dataKey: "name",
|
|
||||||
scaleType: "band" as const,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
width: 500,
|
|
||||||
height: 300,
|
|
||||||
sx: {
|
|
||||||
[`.${axisClasses.left} .${axisClasses.label}`]: {
|
|
||||||
transform: "translate(-20px, 0)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function RoundedBarChart() {
|
export default function RoundedBarChart() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [selectedOption, setSelectedOption] = React.useState("Monthly");
|
const isXsScreen = useMediaQuery(theme.breakpoints.down("sm"));
|
||||||
|
const isSmScreen = useMediaQuery(theme.breakpoints.between("sm", "md"));
|
||||||
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
|
|
||||||
const handleChange = (event: SelectChangeEvent<string>) => {
|
// Fetch role and topStations from Redux state
|
||||||
setSelectedOption(event.target.value);
|
const { user } = useSelector((state: RootState) => state.profileReducer); // Assuming user role is stored in Redux
|
||||||
|
const { topStations } = useSelector(
|
||||||
|
(state: RootState) => state.dashboardReducer
|
||||||
|
);
|
||||||
|
|
||||||
|
// State for filtering
|
||||||
|
const [startDateStations, setStartDateStations] = React.useState("");
|
||||||
|
const [endDateStations, setEndDateStations] = React.useState("");
|
||||||
|
|
||||||
|
// Handle fetching data with date filters
|
||||||
|
const handleFetchData = () => {
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
fetchDashboardData({ startDateStations, endDateStations })
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Responsive chart settings
|
||||||
|
const getChartSettings = () => {
|
||||||
|
const baseSettings = {
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
label: isXsScreen ? "" : "Count",
|
||||||
|
tickFormatter: (value: number) => `${value}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
dataKey: "name",
|
||||||
|
scaleType: "band" as const,
|
||||||
|
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sx: {
|
||||||
|
[`.${axisClasses.left} .${axisClasses.label}`]: {
|
||||||
|
transform: "translate(-10px, 0)",
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Screen-specific settings
|
||||||
|
if (isXsScreen) {
|
||||||
|
return {
|
||||||
|
...baseSettings,
|
||||||
|
width: 280,
|
||||||
|
height: 220,
|
||||||
|
};
|
||||||
|
} else if (isSmScreen) {
|
||||||
|
return {
|
||||||
|
...baseSettings,
|
||||||
|
width: 380,
|
||||||
|
height: 260,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
...baseSettings,
|
||||||
|
width: 500,
|
||||||
|
height: 280,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const chartSetting = getChartSettings();
|
||||||
|
|
||||||
|
// Data transformation for BarChart
|
||||||
|
const chartData = topStations.map((station) => ({
|
||||||
|
name: station?.ChargingStation?.name,
|
||||||
|
count: parseInt(station.count, 10), // Ensure count is a number
|
||||||
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{
|
sx={{
|
||||||
width: "553px",
|
width: "100%",
|
||||||
height: "444px",
|
height: "auto",
|
||||||
|
minHeight: { xs: "360px", sm: "400px", md: "444px" },
|
||||||
borderRadius: "16px",
|
borderRadius: "16px",
|
||||||
|
border: "none",
|
||||||
"*:where([data-mui-color-scheme='dark']) &": {
|
"*:where([data-mui-color-scheme='dark']) &": {
|
||||||
backgroundColor: "#202020",
|
backgroundColor: "#202020",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardContent>
|
<CardContent
|
||||||
<Box display="flex" alignItems="center" color="#F2F2F2">
|
sx={{
|
||||||
|
padding: { xs: 2, md: 3 },
|
||||||
|
"&:last-child": { paddingBottom: { xs: 2, md: 3 } },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Header */}
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
alignItems="center"
|
||||||
|
color="#F2F2F2"
|
||||||
|
flexDirection={isXsScreen ? "column" : "row"}
|
||||||
|
sx={{ mb: isXsScreen ? 2 : 0 }}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h6"
|
variant="h6"
|
||||||
color="#F2F2F2"
|
color="#F2F2F2"
|
||||||
|
align={isXsScreen ? "center" : "left"}
|
||||||
sx={{
|
sx={{
|
||||||
fontFamily: "Gilroy",
|
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontSize: "18px",
|
fontSize: { xs: "16px", sm: "17px", md: "18px" },
|
||||||
lineHeight: "24px",
|
lineHeight: "24px",
|
||||||
|
marginBottom: isXsScreen ? 2 : 0,
|
||||||
|
width: isXsScreen ? "100%" : "auto",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Charge Stats
|
Top Stations Stats
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<FormControl
|
|
||||||
sx={{
|
|
||||||
mt: 2,
|
|
||||||
ml: "auto",
|
|
||||||
backgroundColor: "#202020",
|
|
||||||
color: "#F2F2F2",
|
|
||||||
width: "149px",
|
|
||||||
height: "44px",
|
|
||||||
padding: "12px 16px",
|
|
||||||
gap: "8px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
value={selectedOption}
|
|
||||||
onChange={handleChange}
|
|
||||||
sx={{
|
|
||||||
color: "#D9D8D8",
|
|
||||||
".MuiSelect-icon": {
|
|
||||||
color: "#F2F2F2",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
IconComponent={ExpandMoreIcon}
|
|
||||||
>
|
|
||||||
<MenuItem value="Monthly">Monthly</MenuItem>
|
|
||||||
<MenuItem value="Weekly">Weekly</MenuItem>
|
|
||||||
<MenuItem value="Daily">Daily</MenuItem>
|
|
||||||
<MenuItem value="Yearly">Yearly</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<BarChart
|
{/* Date Filters */}
|
||||||
dataset={data}
|
<Box
|
||||||
series={[
|
display="flex"
|
||||||
{
|
flexDirection={isXsScreen ? "column" : "row"}
|
||||||
dataKey: "v1",
|
gap={2}
|
||||||
label: "Value",
|
mt={2}
|
||||||
color: "skyblue",
|
>
|
||||||
},
|
<TextField
|
||||||
]}
|
type="date"
|
||||||
{...chartSetting}
|
label="Start Date"
|
||||||
/>
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
value={startDateStations}
|
||||||
|
onChange={(e) => setStartDateStations(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#202020",
|
||||||
|
borderRadius: "8px",
|
||||||
|
"& .MuiInputBase-input": {
|
||||||
|
color: "#F2F2F2",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
type="date"
|
||||||
|
label="End Date"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
value={endDateStations}
|
||||||
|
onChange={(e) => setEndDateStations(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#202020",
|
||||||
|
borderRadius: "8px",
|
||||||
|
"& .MuiInputBase-input": {
|
||||||
|
color: "#F2F2F2",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
|
||||||
|
onClick={handleFetchData}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#52ACDF",
|
||||||
|
color: "white",
|
||||||
|
borderRadius: "8px",
|
||||||
|
width: "117px",
|
||||||
|
"&:hover": { backgroundColor: "#439BC1" },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Apply
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Chart */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
width: "100%",
|
||||||
|
mt: 4,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<BarChart
|
||||||
|
borderRadius={0}
|
||||||
|
dataset={chartData}
|
||||||
|
series={[
|
||||||
|
{
|
||||||
|
dataKey: "count",
|
||||||
|
color: "#52ACDF",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
layout="vertical"
|
||||||
|
{...chartSetting}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|
8
src/global.d.ts
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
declare module "*.css";
|
||||||
|
|
||||||
|
declare module "@mui/styles/defaultTheme" {
|
||||||
|
interface DefaultTheme extends Theme {
|
||||||
|
vars: object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,24 @@
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
/* font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
font-family: "Gilroy";
|
||||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
||||||
sans-serif; */
|
|
||||||
font-family: "Gliroy";
|
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mui-typography {
|
||||||
|
font-family: "Gilroy", sans-serif !important;
|
||||||
|
background-color: rgb(7, 127, 233);
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-1w8ddxu-MuiBarElement-root {
|
||||||
|
width: 19px !important;
|
||||||
|
border-radius: 50px !important;
|
||||||
|
rx: 8;
|
||||||
|
ry: 8
|
||||||
|
}
|
||||||
|
|
|
@ -43,9 +43,10 @@ const DashboardLayout: React.FC<LayoutProps> = ({ customStyles }) => {
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
height: "100vh",
|
height: "100vh",
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
backgroundColor: theme.vars
|
// backgroundColor: theme.vars
|
||||||
? `rgba(${theme.vars.palette.background.defaultChannel} / 1)`
|
// ? `rgba(${theme.vars.palette.background.defaultChannel} / 1)`
|
||||||
: theme.palette.background.default,
|
// : theme.palette.background.default,
|
||||||
|
backgroundColor: theme.palette.background.default,
|
||||||
overflow: "auto",
|
overflow: "auto",
|
||||||
...customStyles,
|
...customStyles,
|
||||||
mt: { xs: 8, md: 0 },
|
mt: { xs: 8, md: 0 },
|
||||||
|
|
|
@ -9,7 +9,6 @@ import {
|
||||||
TextField,
|
TextField,
|
||||||
Typography,
|
Typography,
|
||||||
Grid,
|
Grid,
|
||||||
|
|
||||||
Link,
|
Link,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
@ -23,6 +22,7 @@ import { Visibility, VisibilityOff } from "@mui/icons-material";
|
||||||
import { Card, SignInContainer } from "./styled.css.tsx";
|
import { Card, SignInContainer } from "./styled.css.tsx";
|
||||||
import { CustomIconButton } from "../../../components/AddUserModal/styled.css.tsx";
|
import { CustomIconButton } from "../../../components/AddUserModal/styled.css.tsx";
|
||||||
import { AppDispatch } from "../../../redux/store/store.ts";
|
import { AppDispatch } from "../../../redux/store/store.ts";
|
||||||
|
|
||||||
interface ILoginForm {
|
interface ILoginForm {
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
|
@ -35,7 +35,8 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { errors, isValid },trigger
|
formState: { errors, isValid },
|
||||||
|
trigger,
|
||||||
} = useForm<ILoginForm>({ mode: "onChange" });
|
} = useForm<ILoginForm>({ mode: "onChange" });
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
const router = useNavigate();
|
const router = useNavigate();
|
||||||
|
@ -47,17 +48,17 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const togglePasswordVisibility = (e: React.MouseEvent) => {
|
const togglePasswordVisibility = (e: React.MouseEvent) => {
|
||||||
e.preventDefault(); // Prevent focus loss
|
e.preventDefault();
|
||||||
setShowPassword((prev) => !prev);
|
setShowPassword((prev) => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit: SubmitHandler<ILoginForm> = async (data: ILoginForm) => {
|
const onSubmit: SubmitHandler<ILoginForm> = async (data: ILoginForm) => {
|
||||||
const isValid = await trigger(); // This triggers validation for all fields
|
const isValid = await trigger();
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
return; // Stop submission if there are errors
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const response = await dispatch(loginUser(data)).unwrap();
|
const response = await dispatch(loginUser(data)).unwrap();
|
||||||
if (response?.data?.token) {
|
if (response?.data?.token) {
|
||||||
|
@ -71,66 +72,90 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
return (
|
return (
|
||||||
<AppTheme {...props}>
|
<AppTheme {...props}>
|
||||||
<SignInContainer direction="column" justifyContent="space-between">
|
<SignInContainer direction="column" justifyContent="space-between">
|
||||||
<Grid container sx={{ height: "100vh" }}>
|
<Grid container sx={{ minHeight: "100vh" }}>
|
||||||
{/* Image Section */}
|
|
||||||
<Grid
|
<Grid
|
||||||
item
|
item
|
||||||
xs={0}
|
xs={0}
|
||||||
sm={0}
|
sm={0}
|
||||||
md={7}
|
md={7}
|
||||||
sx={{
|
sx={{
|
||||||
background: `url('/mainPageLogo.png') center/cover no-repeat`,
|
background: `url('/Login.svg') center/cover no-repeat`,
|
||||||
// height: { xs: "0%", sm: "50%", md: "100%" },
|
|
||||||
backgroundSize: "cover",
|
backgroundSize: "cover",
|
||||||
display: { xs: "none", md: "block" }, // Hide the image on xs and sm screens
|
display: { xs: "none", md: "block" },
|
||||||
}}
|
position: "relative",
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Form Section */}
|
|
||||||
<Grid
|
|
||||||
item
|
|
||||||
xs={12}
|
|
||||||
md={5}
|
|
||||||
width="408px"
|
|
||||||
height="498px"
|
|
||||||
sx={{
|
|
||||||
backgroundColor: "black",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
flexDirection: "column",
|
|
||||||
padding: { xs: "2rem", md: "3rem", lg: "3rem" },
|
|
||||||
height: "auto",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
textAlign: "center",
|
position: "absolute",
|
||||||
marginBottom: "1rem",
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
display: { xs: "none", md: "block" },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src="/evLogo.png"
|
src="/evLogo.png"
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
style={{
|
style={{
|
||||||
justifyContent: "center",
|
width: "250px",
|
||||||
width: "180px",
|
|
||||||
height: "auto",
|
height: "auto",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Form Section */}
|
||||||
|
<Grid
|
||||||
|
item
|
||||||
|
xs={12}
|
||||||
|
md={5}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "black",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
flexDirection: "column",
|
||||||
|
padding: { xs: "1.5rem", sm: "2rem", md: "3rem" },
|
||||||
|
position: "relative",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: { xs: "flex", md: "none" },
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
width: "100%",
|
||||||
|
mb: 4,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="/evLogo.png"
|
||||||
|
alt="Logo"
|
||||||
|
style={{
|
||||||
|
width: "200px",
|
||||||
|
maxWidth: "100%",
|
||||||
|
height: "auto",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
variant="h3"
|
variant="h3"
|
||||||
width={"408px"}
|
|
||||||
height={"46px"}
|
|
||||||
sx={{
|
sx={{
|
||||||
color: "white",
|
color: "white",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
fontSize: {
|
fontSize: {
|
||||||
xs: "2rem",
|
xs: "1.8rem",
|
||||||
sm: "2.2rem",
|
sm: "2.2rem",
|
||||||
md: "36px",
|
md: "2.5rem",
|
||||||
},
|
},
|
||||||
|
width: "100%",
|
||||||
|
mb: { xs: 2, md: 3 },
|
||||||
|
mt: { xs: 0, md: 0 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Welcome Back!
|
Welcome Back!
|
||||||
|
@ -139,11 +164,12 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
<Card
|
<Card
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{
|
sx={{
|
||||||
width: { xs: "100%", sm: "300px", lg: "408px" },
|
width: { xs: "100%", sm: "90%", md: "90%", lg: "408px" },
|
||||||
height:{lg:"428px"},
|
maxWidth: "408px",
|
||||||
padding: "24px",
|
minHeight: { xs: "auto", md: "428px" },
|
||||||
|
padding: { xs: "16px", sm: "20px", md: "24px" },
|
||||||
borderRadius: "9px",
|
borderRadius: "9px",
|
||||||
border: "1px solidrgb(45, 48, 49)",
|
border: "none",
|
||||||
"*:where([data-mui-color-scheme='dark']) &": {
|
"*:where([data-mui-color-scheme='dark']) &": {
|
||||||
backgroundColor: "#1E1E1E",
|
backgroundColor: "#1E1E1E",
|
||||||
},
|
},
|
||||||
|
@ -156,7 +182,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
gap: 2,
|
gap: { xs: 1.5, md: 2 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
|
@ -165,8 +191,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
sx={{
|
sx={{
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
color: "white",
|
color: "white",
|
||||||
fontFamily: "Gilroy",
|
fontSize: { xs: "20px", md: "24px" },
|
||||||
fontSize: "24px",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Login
|
Login
|
||||||
|
@ -177,24 +202,24 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
sx={{
|
sx={{
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
color: "white",
|
color: "white",
|
||||||
fontFamily: "Gilroy",
|
fontSize: { xs: "14px", md: "16px" },
|
||||||
fontSize: "16px",
|
mb: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Log in with your email and password
|
Log in with your email and password
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{/* -------------------------------- Email Field ----------------- */}
|
{/* Email Field */}
|
||||||
<FormControl sx={{ width: "100%" }}>
|
<FormControl sx={{ width: "100%" }}>
|
||||||
<FormLabel
|
<FormLabel
|
||||||
htmlFor="email"
|
htmlFor="email"
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: {
|
fontSize: {
|
||||||
xs: "0.9rem",
|
xs: "0.875rem",
|
||||||
sm: "1rem",
|
sm: "1rem",
|
||||||
},
|
},
|
||||||
color: "white",
|
color: "white",
|
||||||
fontFamily: "Gilroy, sans-serif",
|
mb: 0.5,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Email
|
Email
|
||||||
|
@ -233,12 +258,10 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
}
|
}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
sx: {
|
sx: {
|
||||||
height: "50px",
|
height: { xs: "45px", md: "50px" },
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
"#1E1F1F",
|
"#1E1F1F",
|
||||||
fontFamily:
|
|
||||||
"Gilroy, sans-serif",
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -266,7 +289,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
"& input": {
|
"& input": {
|
||||||
color: "white",
|
color: "white",
|
||||||
fontSize: {
|
fontSize: {
|
||||||
xs: "0.9rem",
|
xs: "0.875rem",
|
||||||
sm: "1rem",
|
sm: "1rem",
|
||||||
},
|
},
|
||||||
fontFamily:
|
fontFamily:
|
||||||
|
@ -285,17 +308,18 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
{/* -------------------------------- Password Field ----------------- */}
|
{/* Password Field */}
|
||||||
<FormControl sx={{ width: "100%" }}>
|
<FormControl sx={{ width: "100%" }}>
|
||||||
<FormLabel
|
<FormLabel
|
||||||
htmlFor="password"
|
htmlFor="password"
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: {
|
fontSize: {
|
||||||
xs: "0.9rem",
|
xs: "0.875rem",
|
||||||
sm: "1rem",
|
sm: "1rem",
|
||||||
},
|
},
|
||||||
color: "white",
|
color: "white",
|
||||||
fontFamily: "Gilroy, sans-serif",
|
fontFamily: "Gilroy, sans-serif",
|
||||||
|
mb: 0.5,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Password
|
Password
|
||||||
|
@ -342,6 +366,9 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
: "primary"
|
: "primary"
|
||||||
}
|
}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
|
sx: {
|
||||||
|
height: { xs: "45px", md: "50px" },
|
||||||
|
},
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
<CustomIconButton
|
<CustomIconButton
|
||||||
|
@ -384,18 +411,14 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
"& input": {
|
"& input": {
|
||||||
color: "white",
|
color: "white",
|
||||||
fontSize: {
|
fontSize: {
|
||||||
xs: "0.9rem",
|
xs: "0.875rem",
|
||||||
sm: "1rem",
|
sm: "1rem",
|
||||||
},
|
},
|
||||||
fontFamily:
|
|
||||||
"Gilroy, sans-serif",
|
|
||||||
},
|
},
|
||||||
"& .MuiInputBase-input::placeholder":
|
"& .MuiInputBase-input::placeholder":
|
||||||
{
|
{
|
||||||
color: "white",
|
color: "white",
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
fontFamily:
|
|
||||||
"Gilroy, sans-serif",
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -403,13 +426,16 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
|
{/* Remember me and Forgot Password */}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
color: "white",
|
color: "white",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
flexWrap: "wrap",
|
flexWrap: { xs: "wrap", sm: "nowrap" },
|
||||||
|
gap: 1,
|
||||||
|
mt: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
|
@ -417,10 +443,8 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
<Checkbox
|
<Checkbox
|
||||||
value="remember"
|
value="remember"
|
||||||
sx={{
|
sx={{
|
||||||
width: 20,
|
width: { xs: 16, md: 20 },
|
||||||
height: 20,
|
height: { xs: 16, md: 20 },
|
||||||
fontFamily:
|
|
||||||
"Gilroy, sans-serif",
|
|
||||||
border: "2px solid #4b5255",
|
border: "2px solid #4b5255",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
|
@ -441,7 +465,19 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
label="Remember me"
|
label={
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: {
|
||||||
|
xs: "0.75rem",
|
||||||
|
sm: "0.875rem",
|
||||||
|
md: "1rem"
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Remember me
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
|
@ -451,9 +487,13 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
variant="body2"
|
variant="body2"
|
||||||
sx={{
|
sx={{
|
||||||
alignSelf: "center",
|
alignSelf: "center",
|
||||||
fontFamily: "Gilroy, sans-serif",
|
|
||||||
color: "#01579b",
|
color: "#01579b",
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
|
fontSize: {
|
||||||
|
xs: "0.75rem",
|
||||||
|
sm: "0.875rem",
|
||||||
|
md: "1rem"
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Forgot password?
|
Forgot password?
|
||||||
|
@ -463,18 +503,22 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
open={open}
|
open={open}
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Login Button */}
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
fullWidth
|
fullWidth
|
||||||
disabled={!isValid}
|
disabled={!isValid}
|
||||||
sx={{
|
sx={{
|
||||||
color: "white",
|
color: "#ffffff !important",
|
||||||
fontFamily: "Gilroy, sans-serif",
|
fontWeight: 500,
|
||||||
backgroundColor: "#52ACDF",
|
backgroundColor: "#52ACDF",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: "#52ACDF",
|
backgroundColor: "#52ACDF",
|
||||||
opacity: 0.9,
|
|
||||||
},
|
},
|
||||||
|
padding: { xs: "8px 0", md: "10px 0" },
|
||||||
|
mt: { xs: 2, md: 3 },
|
||||||
|
fontSize: { xs: "0.875rem", md: "1rem" },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Login
|
Login
|
||||||
|
@ -486,4 +530,4 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
|
||||||
</SignInContainer>
|
</SignInContainer>
|
||||||
</AppTheme>
|
</AppTheme>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -245,7 +245,7 @@ export default function SignUp(props: { disableCustomTheme?: boolean }) {
|
||||||
<FormLabel htmlFor="phone">Phone Number</FormLabel>
|
<FormLabel htmlFor="phone">Phone Number</FormLabel>
|
||||||
<MuiPhoneNumber
|
<MuiPhoneNumber
|
||||||
defaultCountry="in"
|
defaultCountry="in"
|
||||||
onChange={handlePhoneChange}
|
onChange={(value) => handlePhoneChange(value as string)}
|
||||||
value={control._formValues.phone}
|
value={control._formValues.phone}
|
||||||
required
|
required
|
||||||
error={!!errors.phone}
|
error={!!errors.phone}
|
||||||
|
|
|
@ -55,7 +55,7 @@ const LandingPage = () => {
|
||||||
radial-gradient(circle at 30%, rgb(241, 201, 119) 100%, rgba(255, 204, 102, 0) 50%)
|
radial-gradient(circle at 30%, rgb(241, 201, 119) 100%, rgba(255, 204, 102, 0) 50%)
|
||||||
`,
|
`,
|
||||||
color: "white",
|
color: "white",
|
||||||
minHeight: "100vh",
|
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
//display: "flex", // Ensures the children align correctly
|
//display: "flex", // Ensures the children align correctly
|
||||||
//flexDirection: "column",
|
//flexDirection: "column",
|
||||||
|
@ -322,7 +322,7 @@ const LandingPage = () => {
|
||||||
<Container
|
<Container
|
||||||
maxWidth="lg"
|
maxWidth="lg"
|
||||||
sx={{
|
sx={{
|
||||||
minHeight: "100vh",
|
// minHeight: "100vh",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
// width: "1320px",
|
// width: "1320px",
|
||||||
// height: "349.82px",
|
// height: "349.82px",
|
||||||
|
@ -455,6 +455,374 @@ const LandingPage = () => {
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Container>
|
</Container>
|
||||||
|
<Container
|
||||||
|
maxWidth="lg"
|
||||||
|
sx={{
|
||||||
|
// minHeight: "100vh",
|
||||||
|
textAlign: "center",
|
||||||
|
width: "100%",
|
||||||
|
boxShadow: "0px 8px 20px rgba(166, 210, 235, 0.2)", // Bluish box shadow
|
||||||
|
background:
|
||||||
|
"linear-gradient(135deg, rgba(82, 172, 223, 0.2), rgba(0,0,0,0.3))",
|
||||||
|
borderRadius: "16px",
|
||||||
|
py: 4,
|
||||||
|
px: 3,
|
||||||
|
mt: 10,
|
||||||
|
fontFamily: "Neue Montreal",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h4" fontWeight={700} mb={5}>
|
||||||
|
Key Features
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
position: "relative",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="/iMockup - iPhone.png"
|
||||||
|
alt="iMockup - iPhone"
|
||||||
|
style={{
|
||||||
|
width: "60%",
|
||||||
|
maxWidth: "500px",
|
||||||
|
borderRadius: "10px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
pointerEvents: "none", // Prevents interaction issues
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Top Left */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "5%",
|
||||||
|
left: "5%",
|
||||||
|
transform: "translate(-5%, -5%)",
|
||||||
|
maxWidth: "200px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Arrow pointing to mockup */}
|
||||||
|
<img
|
||||||
|
src="/vector-arrows.png"
|
||||||
|
alt="Arrow"
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
width: "80px",
|
||||||
|
height: "60px",
|
||||||
|
top: "100%",
|
||||||
|
left: "160%",
|
||||||
|
transform:
|
||||||
|
"translate(-50%, -50%) rotate(-20deg)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
fontWeight={400}
|
||||||
|
color="#FFFFFF"
|
||||||
|
fontSize={"20px"}
|
||||||
|
lineHeight={"30px"}
|
||||||
|
>
|
||||||
|
Seamless Navigation
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="#D9D8D8">
|
||||||
|
Effortlessly locate and access EV charging
|
||||||
|
stations with our intuitive map integration.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
{/* Top Right */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "1%",
|
||||||
|
right: "5%",
|
||||||
|
transform: "translate(5%, -5%)",
|
||||||
|
maxWidth: "200px",
|
||||||
|
textAlign: "right",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Arrow pointing to mockup */}
|
||||||
|
<img
|
||||||
|
src="/vector-arrows.png"
|
||||||
|
alt="Arrow"
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
width: "80px",
|
||||||
|
height: "50px",
|
||||||
|
top: "90%",
|
||||||
|
right: "110%",
|
||||||
|
transform:
|
||||||
|
"translate(50%, -50%) rotate(120deg)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
fontWeight={400}
|
||||||
|
color="#FFFFFF"
|
||||||
|
fontSize={"20px"}
|
||||||
|
lineHeight={"30px"}
|
||||||
|
>
|
||||||
|
Live Availability
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="#D9D8D8">
|
||||||
|
View real-time charger availability to plan your
|
||||||
|
trips efficiently.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
{/* Bottom Left */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: "5%",
|
||||||
|
left: "5%",
|
||||||
|
transform: "translate(-5%, 5%)",
|
||||||
|
maxWidth: "200px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Arrow pointing to mockup */}
|
||||||
|
<img
|
||||||
|
src="/vector-arrows.png"
|
||||||
|
alt="Arrow"
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
width: "80px",
|
||||||
|
height: "60px",
|
||||||
|
bottom: "80%",
|
||||||
|
left: "120%",
|
||||||
|
transform:
|
||||||
|
"translate(-50%, 50%) rotate(300deg)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
fontWeight={400}
|
||||||
|
color="#FFFFFF"
|
||||||
|
fontSize={"20px"}
|
||||||
|
lineHeight={"30px"}
|
||||||
|
>
|
||||||
|
Smart Recommendations
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="#D9D8D8">
|
||||||
|
Get personalized station suggestions based on
|
||||||
|
your location and usage patterns.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
{/* Bottom Right */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: "5%",
|
||||||
|
right: "5%",
|
||||||
|
transform: "translate(5%, 5%)",
|
||||||
|
maxWidth: "200px",
|
||||||
|
textAlign: "right",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Arrow pointing to mockup */}
|
||||||
|
<img
|
||||||
|
src="/vector-arrows.png"
|
||||||
|
alt="Arrow"
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
width: "80px",
|
||||||
|
height: "60px",
|
||||||
|
bottom: "100%",
|
||||||
|
right: "200%",
|
||||||
|
transform:
|
||||||
|
"translate(50%, 50%) rotate(-200deg)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
fontWeight={400}
|
||||||
|
color="#FFFFFF"
|
||||||
|
fontSize={"20px"}
|
||||||
|
lineHeight={"30px"}
|
||||||
|
>
|
||||||
|
Secure Payments
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="#D9D8D8">
|
||||||
|
Make hassle-free transactions with our secure
|
||||||
|
payment gateway.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Container>
|
||||||
|
{/* Footer */}
|
||||||
|
<Container
|
||||||
|
maxWidth="lg"
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
width: "100%",
|
||||||
|
boxShadow: "0px 8px 20px rgba(166, 210, 235, 0.2)", // Bluish box shadow
|
||||||
|
background:
|
||||||
|
"linear-gradient(135deg, rgba(82, 172, 223, 0.2), rgba(0,0,0,0.3))",
|
||||||
|
borderRadius: "16px",
|
||||||
|
py: 4,
|
||||||
|
px: 3,
|
||||||
|
mt: 10,
|
||||||
|
fontFamily: "Neue Montreal",
|
||||||
|
height: "261px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
// minHeight: "100vh",
|
||||||
|
textAlign: "center",
|
||||||
|
|
||||||
|
py: 4,
|
||||||
|
px: 3,
|
||||||
|
mt: 2,
|
||||||
|
fontFamily: "Neue Montreal",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
position: "relative",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Primary Image */}
|
||||||
|
<img
|
||||||
|
src="/dev-bg.png"
|
||||||
|
alt="Developer"
|
||||||
|
style={{
|
||||||
|
width: "80px",
|
||||||
|
marginRight: "20px",
|
||||||
|
position: "relative",
|
||||||
|
zIndex: 1, // Ensure it's layered on top
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Overlapping Image */}
|
||||||
|
<img
|
||||||
|
src="/developer.png"
|
||||||
|
alt="developer"
|
||||||
|
style={{
|
||||||
|
width: "80px",
|
||||||
|
position: "absolute",
|
||||||
|
top: "10px",
|
||||||
|
left: "20px",
|
||||||
|
zIndex: 2,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography
|
||||||
|
fontFamily={"Inter"}
|
||||||
|
fontWeight={500}
|
||||||
|
fontSize={"40px"}
|
||||||
|
lineHeight={"100%"}
|
||||||
|
color="#FFFFFF"
|
||||||
|
>
|
||||||
|
Get your application developed by our certified
|
||||||
|
experts today!
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#52ACDF",
|
||||||
|
color: "white",
|
||||||
|
borderRadius: "8px",
|
||||||
|
width: "160px",
|
||||||
|
height: "54px",
|
||||||
|
fontFamily: "Neue Montreal",
|
||||||
|
textTransform: "none",
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: "18px",
|
||||||
|
lineHeight: "100%",
|
||||||
|
|
||||||
|
"&:hover": { backgroundColor: "#439BC1" },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Schedule a Call
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Container>
|
||||||
|
|
||||||
|
<Container
|
||||||
|
maxWidth="lg"
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
width: "100%",
|
||||||
|
boxShadow: "0px 8px 20px rgba(166, 210, 235, 0.2)", // Bluish box shadow
|
||||||
|
background:
|
||||||
|
"linear-gradient(135deg, rgba(82, 172, 223, 0.2), rgba(0,0,0,0.3))",
|
||||||
|
borderRadius: "16px",
|
||||||
|
py: 4,
|
||||||
|
px: 3,
|
||||||
|
mt: 10,
|
||||||
|
fontFamily: "Neue Montreal",
|
||||||
|
height: "auto", // Dynamically adjust height to content
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
py: 4,
|
||||||
|
px: 3,
|
||||||
|
mt: 2,
|
||||||
|
fontFamily: "Neue Montreal",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="h5"
|
||||||
|
fontWeight={600}
|
||||||
|
fontFamily={"Inter"}
|
||||||
|
fontSize={"40px"}
|
||||||
|
lineHeight={"100%"}
|
||||||
|
>
|
||||||
|
Your{" "}
|
||||||
|
<span style={{ color: "#52ACDF" }}>
|
||||||
|
Perfect Experience
|
||||||
|
</span>
|
||||||
|
, Just a Tap Away!
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
my: 2,
|
||||||
|
fontFamily: "Inter",
|
||||||
|
fontWeight: 400,
|
||||||
|
fontSize: "20px",
|
||||||
|
color: "#FFFFFF",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Discover the smartest way to charge your electric
|
||||||
|
vehicle. DigiEV's cutting-edge platform empowers you
|
||||||
|
with effortless access to EV charging stations,
|
||||||
|
real-time availability updates, and powerful tools to
|
||||||
|
plan your journey. Make every drive electric, efficient,
|
||||||
|
and extraordinary.
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
gap: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="/google_play.png"
|
||||||
|
alt="Google Play"
|
||||||
|
style={{ width: "120px" }}
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src="/apple_store.png"
|
||||||
|
alt="App Store"
|
||||||
|
style={{ width: "120px" }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ import managerReducer from "../redux/slices/managerSlice.ts";
|
||||||
import stationReducer from "../redux/slices/stationSlice.ts";
|
import stationReducer from "../redux/slices/stationSlice.ts";
|
||||||
import slotReducer from "../redux/slices/slotSlice.ts";
|
import slotReducer from "../redux/slices/slotSlice.ts";
|
||||||
import bookReducer from "../redux/slices/bookSlice.ts";
|
import bookReducer from "../redux/slices/bookSlice.ts";
|
||||||
|
import dashboardReducer from "../redux/slices/dashboardSlice.ts";
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
authReducer,
|
authReducer,
|
||||||
|
@ -23,7 +23,8 @@ const rootReducer = combineReducers({
|
||||||
stationReducer,
|
stationReducer,
|
||||||
slotReducer,
|
slotReducer,
|
||||||
bookReducer,
|
bookReducer,
|
||||||
// Add other reducers here...
|
dashboardReducer,
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type RootState = ReturnType<typeof rootReducer>;
|
export type RootState = ReturnType<typeof rootReducer>;
|
||||||
|
|
|
@ -19,6 +19,8 @@ interface Booking {
|
||||||
startTime: string;
|
startTime: string;
|
||||||
endTime: string;
|
endTime: string;
|
||||||
carDetails: CarDetails;
|
carDetails: CarDetails;
|
||||||
|
carNames: string[]; // For car names
|
||||||
|
carPorts: string[]; // For car ports
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BookingState {
|
interface BookingState {
|
||||||
|
|
94
src/redux/slices/dashboardSlice.ts
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
|
||||||
|
import http from "../../lib/https";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
// Define interfaces for the dashboard data structure
|
||||||
|
interface CarPortCount {
|
||||||
|
carPort: string;
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TopStation {
|
||||||
|
stationId: number;
|
||||||
|
count: string;
|
||||||
|
ChargingStation: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DashboardState {
|
||||||
|
totalAdmins: number;
|
||||||
|
totalManagers: number;
|
||||||
|
totalUsers: number;
|
||||||
|
totalStations: number;
|
||||||
|
carPortCounts: CarPortCount[];
|
||||||
|
topStations: TopStation[];
|
||||||
|
totalBookings: number;
|
||||||
|
loading: boolean;
|
||||||
|
error: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: DashboardState = {
|
||||||
|
totalAdmins: 0,
|
||||||
|
totalManagers: 0,
|
||||||
|
totalUsers: 0,
|
||||||
|
totalStations: 0,
|
||||||
|
carPortCounts: [],
|
||||||
|
topStations: [],
|
||||||
|
totalBookings: 0,
|
||||||
|
loading: false,
|
||||||
|
error: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Async thunk for fetching dashboard data
|
||||||
|
export const fetchDashboardData = createAsyncThunk<
|
||||||
|
DashboardState,
|
||||||
|
{ startDateBookings?: string; endDateBookings?: string; startDateStations?: string; endDateStations?: string}, // Accept startDate and endDate as optional parameters
|
||||||
|
{ rejectValue: string }
|
||||||
|
>("dashboard/fetchDashboardData", async (params, { rejectWithValue }) => {
|
||||||
|
try {
|
||||||
|
const response = await http.get("/dashboard", { params }); // Pass startDate and endDate as query params
|
||||||
|
return response.data;
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error("Error Fetching Dashboard Data: " + error.message);
|
||||||
|
return rejectWithValue(
|
||||||
|
error?.response?.data?.message || "An error occurred"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Redux slice for the dashboard
|
||||||
|
const dashboardSlice = createSlice({
|
||||||
|
name: "dashboard",
|
||||||
|
initialState,
|
||||||
|
reducers: {},
|
||||||
|
extraReducers: (builder) => {
|
||||||
|
builder
|
||||||
|
.addCase(fetchDashboardData.pending, (state) => {
|
||||||
|
state.loading = true;
|
||||||
|
state.error = null;
|
||||||
|
})
|
||||||
|
.addCase(
|
||||||
|
fetchDashboardData.fulfilled,
|
||||||
|
(state, action: PayloadAction<DashboardState>) => {
|
||||||
|
state.loading = false;
|
||||||
|
state.totalAdmins = action.payload.totalAdmins;
|
||||||
|
state.totalManagers = action.payload.totalManagers;
|
||||||
|
state.totalUsers = action.payload.totalUsers;
|
||||||
|
state.totalStations = action.payload.totalStations;
|
||||||
|
state.carPortCounts = action.payload.carPortCounts;
|
||||||
|
state.topStations = action.payload.topStations;
|
||||||
|
state.totalBookings = action.payload.totalBookings;
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
.addCase(fetchDashboardData.rejected, (state, action) => {
|
||||||
|
state.loading = false;
|
||||||
|
state.error =
|
||||||
|
action.payload || "Failed to fetch dashboard data";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default dashboardSlice.reducer;
|
|
@ -6,19 +6,12 @@ import { dataDisplayCustomizations } from "./customizations/dataDisplay";
|
||||||
import { feedbackCustomizations } from "./customizations/feedback";
|
import { feedbackCustomizations } from "./customizations/feedback";
|
||||||
import { navigationCustomizations } from "./customizations/navigation";
|
import { navigationCustomizations } from "./customizations/navigation";
|
||||||
import { surfacesCustomizations } from "./customizations/surfaces";
|
import { surfacesCustomizations } from "./customizations/surfaces";
|
||||||
import { colorSchemes, typography, shadows, shape } from "./themePrimitives";
|
import { colorSchemes, shadows, shape } from "./themePrimitives";
|
||||||
|
|
||||||
|
|
||||||
declare module "@mui/styles/defaultTheme" {
|
|
||||||
interface DefaultTheme extends Theme {
|
|
||||||
vars: object;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AppThemeProps {
|
interface AppThemeProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
/**
|
|
||||||
* This is for the docs site. You can ignore it or remove it.
|
|
||||||
*/
|
|
||||||
disableCustomTheme?: boolean;
|
disableCustomTheme?: boolean;
|
||||||
themeComponents?: ThemeOptions["components"];
|
themeComponents?: ThemeOptions["components"];
|
||||||
}
|
}
|
||||||
|
@ -30,21 +23,23 @@ export default function AppTheme(props: AppThemeProps) {
|
||||||
? {}
|
? {}
|
||||||
: createTheme({
|
: createTheme({
|
||||||
palette: {
|
palette: {
|
||||||
mode: "dark", // Enforcing dark mode across the app
|
mode: "dark",
|
||||||
background: {
|
background: {
|
||||||
default: "#111111", // Dark background color
|
default: "#111111",
|
||||||
paper: "#1e1e1e", // Darker background for cards, containers, etc.
|
paper: "#1e1e1e",
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
primary: "#ffffff", // White text for readability
|
primary: "#ffffff",
|
||||||
secondary: "#b0b0b0", // Lighter secondary text
|
secondary: "#b0b0b0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily: "Gilroy, sans-serif",
|
||||||
|
},
|
||||||
cssVariables: {
|
cssVariables: {
|
||||||
colorSchemeSelector: "data-mui-color-scheme",
|
colorSchemeSelector: "data-mui-color-scheme",
|
||||||
cssVarPrefix: "template",
|
cssVarPrefix: "template",
|
||||||
},
|
},
|
||||||
typography,
|
|
||||||
shadows,
|
shadows,
|
||||||
shape,
|
shape,
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -11,10 +11,22 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"types": ["react", "react-dom"],
|
"types": [
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"react",
|
||||||
|
"react-dom"
|
||||||
|
],
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": [
|
||||||
|
"./src/*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|