Complete Landing Page and APi Integration for Dashboard

This commit is contained in:
jaanvi 2025-04-04 18:58:57 +05:30
commit fed0e9db04
31 changed files with 1576 additions and 591 deletions

View file

@ -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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 MiB

BIN
public/apple_store.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

BIN
public/dev-bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

BIN
public/developer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
public/google_play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
public/iMockup - iPhone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -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>

View file

@ -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",
}} }}
> >

View file

@ -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}>

View file

@ -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

View file

@ -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>

View file

@ -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>
); );
} }

View file

@ -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" && {

View file

@ -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>
); );
} }

View file

@ -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> );
);
} }

View file

@ -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>
);
}

View file

@ -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
View file

@ -0,0 +1,8 @@
declare module "*.css";
declare module "@mui/styles/defaultTheme" {
interface DefaultTheme extends Theme {
vars: object;
}
}

View file

@ -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
}

View file

@ -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 },

View file

@ -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>
); );
} }

View file

@ -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}

View file

@ -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>
); );
}; };

View file

@ -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>;

View file

@ -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 {

View 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;

View file

@ -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: {

View file

@ -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/*"
]
} }
} }
} }