diff --git a/package-lock.json b/package-lock.json index 73c75b5..47d6f99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,19 @@ "name": "react-chart-js", "version": "0.1.0", "dependencies": { + "@emotion/react": "^11.11.0", + "@emotion/styled": "^11.11.0", + "@mui/icons-material": "^5.11.16", + "@mui/material": "^5.13.1", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "chart.js": "^4.3.0", + "chartjs-plugin-datalabels": "^2.2.0", "react": "^18.2.0", + "react-chartjs-2": "^5.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.11.2", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" } @@ -2137,6 +2145,158 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", + "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.0.tgz", + "integrity": "sha512-ZSK3ZJsNkwfjT3JpDAWJZlrGD81Z3ytNDsxw1LKq1o+xkmO5pnWfr6gmCC8gHEFf3nSSX/09YrG67jybNPxSUw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz", + "integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/styled": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", + "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/is-prop-valid": "^1.2.1", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -2999,11 +3159,272 @@ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.1.tgz", + "integrity": "sha512-xrkDCeu3JQE+JjJUnJnOrdQJMXwKhbV4AW+FRjMIj5i9cHK3BAuatG/iqbf1M+jklVWLk0KdbgioKwK+03aYbA==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@emotion/is-prop-valid": "^1.2.0", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.13.1", + "@popperjs/core": "^2.11.7", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/base/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.1.tgz", + "integrity": "sha512-qDHtNDO72NcBQMhaWBt9EZMvNiO+OXjPg5Sdk/6LgRDw6Zr3HdEZ5n2FJ/qtYsaT/okGyCuQavQkcZCOCEVf/g==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + } + }, + "node_modules/@mui/icons-material": { + "version": "5.11.16", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.11.16.tgz", + "integrity": "sha512-oKkx9z9Kwg40NtcIajF9uOXhxiyTZrrm9nmIJ4UjkU2IdHpd4QVLbCc/5hZN/y0C6qzi2Zlxyr9TGddQx2vx2A==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.13.1.tgz", + "integrity": "sha512-qSnbJZer8lIuDYFDv19/t3s0AXYY9SxcOdhCnGvetRSfOG4gy3TkiFXNCdW5OLNveTieiMpOuv46eXUmE3ZA6A==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/base": "5.0.0-beta.1", + "@mui/core-downloads-tracker": "^5.13.1", + "@mui/system": "^5.13.1", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.13.1", + "@types/react-transition-group": "^4.4.6", + "clsx": "^1.2.1", + "csstype": "^3.1.2", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/@mui/private-theming": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.13.1.tgz", + "integrity": "sha512-HW4npLUD9BAkVppOUZHeO1FOKUJWAwbpy0VQoGe3McUYTlck1HezGHQCfBQ5S/Nszi7EViqiimECVl9xi+/WjQ==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/utils": "^5.13.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.12.3", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.12.3.tgz", + "integrity": "sha512-AhZtiRyT8Bjr7fufxE/mLS+QJ3LxwX1kghIcM2B2dvJzSSg9rnIuXDXM959QfUVIM3C8U4x3mgVoPFMQJvc4/g==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@emotion/cache": "^11.10.8", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.13.1.tgz", + "integrity": "sha512-BsDUjhiO6ZVAvzKhnWBHLZ5AtPJcdT+62VjnRLyA4isboqDKLg4fmYIZXq51yndg/soDK9RkY5lYZwEDku13Ow==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/private-theming": "^5.13.1", + "@mui/styled-engine": "^5.12.3", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.13.1", + "clsx": "^1.2.1", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz", + "integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.1.tgz", + "integrity": "sha512-6lXdWwmlUbEU2jUI8blw38Kt+3ly7xkmV9ljzY4Q20WhsJMWiNry9CX8M+TaP/HbtuyR8XKsdMgQW7h7MM3n3A==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@types/prop-types": "^15.7.5", + "@types/react-is": "^18.2.0", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -3113,6 +3534,23 @@ } } }, + "node_modules/@popperjs/core": { + "version": "2.11.7", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", + "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@remix-run/router": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.6.2.tgz", + "integrity": "sha512-LzqpSrMK/3JBAVBI9u3NWtOhWNw5AMQfrUFYB0+bDHTSw17z++WJLsPsxAuK+oSddsxk4d7F/JcdDPM1M5YAhA==", + "engines": { + "node": ">=14" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -4199,6 +4637,22 @@ "@types/react": "*" } }, + "node_modules/@types/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-1vz2yObaQkLL7YFe/pme2cpvDsCwI1WXIfL+5eLz0MI9gFG24Re16RzUsI8t9XZn9ZWvgLNDrJBmrqXJO7GNQQ==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", + "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -5679,6 +6133,25 @@ "node": ">=10" } }, + "node_modules/chart.js": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.0.tgz", + "integrity": "sha512-ynG0E79xGfMaV2xAHdbhwiPLczxnNNnasrmPEXriXsPJGjmhOBYzFVEsB65w2qMDz+CaBJJuJD0inE/ab/h36g==", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=7" + } + }, + "node_modules/chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "peerDependencies": { + "chart.js": ">=3.0.0" + } + }, "node_modules/check-types": { "version": "11.2.2", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.2.tgz", @@ -5777,6 +6250,14 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -6688,6 +7169,15 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -8068,6 +8558,11 @@ "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -8697,6 +9192,19 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -14217,6 +14725,15 @@ "node": ">=14" } }, + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -14364,6 +14881,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.11.2.tgz", + "integrity": "sha512-74z9xUSaSX07t3LM+pS6Un0T55ibUE/79CzfZpy5wsPDZaea1F8QkrsiyRnA2YQ7LwE/umaydzXZV80iDCPkMg==", + "dependencies": { + "@remix-run/router": "1.6.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.11.2.tgz", + "integrity": "sha512-JNbKtAeh1VSJQnH6RvBDNhxNwemRj7KxCzc5jb7zvDSKRnPWIFj9pO+eXqjM69gQJ0r46hSz1x4l9y0651DKWw==", + "dependencies": { + "@remix-run/router": "1.6.2", + "react-router": "6.11.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -14436,6 +14983,21 @@ } } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -15576,6 +16138,11 @@ "postcss": "^8.2.15" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/sucrase": { "version": "3.32.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", diff --git a/package.json b/package.json index 9732411..607cd03 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,19 @@ "version": "0.1.0", "private": true, "dependencies": { + "@emotion/react": "^11.11.0", + "@emotion/styled": "^11.11.0", + "@mui/icons-material": "^5.11.16", + "@mui/material": "^5.13.1", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "chart.js": "^4.3.0", + "chartjs-plugin-datalabels": "^2.2.0", "react": "^18.2.0", + "react-chartjs-2": "^5.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.11.2", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }, diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index a11777c..0000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/public/index.html b/public/index.html index aa069f2..af76a7f 100644 --- a/public/index.html +++ b/public/index.html @@ -2,42 +2,16 @@ - + - - - - - React App + content="Web site created using create-react-app" /> + React | Chart
- diff --git a/public/logo192.png b/public/logo192.png deleted file mode 100644 index fc44b0a..0000000 Binary files a/public/logo192.png and /dev/null differ diff --git a/public/logo512.png b/public/logo512.png deleted file mode 100644 index a4e47a6..0000000 Binary files a/public/logo512.png and /dev/null differ diff --git a/public/manifest.json b/public/manifest.json deleted file mode 100644 index 080d6c7..0000000 --- a/public/manifest.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "short_name": "React App", - "name": "Create React App Sample", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/public/pie_statistics_icon.png b/public/pie_statistics_icon.png new file mode 100644 index 0000000..23da662 Binary files /dev/null and b/public/pie_statistics_icon.png differ diff --git a/src/App.css b/src/App.css index 74b5e05..e69de29 100644 --- a/src/App.css +++ b/src/App.css @@ -1,38 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/src/App.js b/src/App.js index 3784575..ea2a049 100644 --- a/src/App.js +++ b/src/App.js @@ -1,25 +1,30 @@ -import logo from './logo.svg'; -import './App.css'; +import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; +import { Container } from '@mui/material'; + +import MiniDrawer from './components/SideBar'; +import Dashboard from './Pages/Dashboard/index'; +import Inventory from './Pages/Inventory/index'; +import Orders from './Pages/Orders/index'; +import Customers from './Pages/Customers'; +import DataContext from "./Dynamic Data/dataContext"; function App() { return ( -
-
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - -
-
+ + + + + + } /> + } /> + } /> + } /> + } /> + + + + ); } -export default App; +export default App; \ No newline at end of file diff --git a/src/App.test.js b/src/App.test.js deleted file mode 100644 index 1f03afe..0000000 --- a/src/App.test.js +++ /dev/null @@ -1,8 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/src/Dynamic Data/DynamicData.js b/src/Dynamic Data/DynamicData.js new file mode 100644 index 0000000..c39a4d4 --- /dev/null +++ b/src/Dynamic Data/DynamicData.js @@ -0,0 +1,17 @@ +export const fetchCart = async () => { + const response = await fetch('https://dummyjson.com/carts') + if (!response.ok) { + throw new Error('Carts could not be fetched!') + } else { + return response.json() + } +} + +export const fetchProducts = async () => { + const response = await fetch('https://dummyjson.com/products?limit=30') + if (!response.ok) { + throw new Error('Products could not be fetched!') + } else { + return response.json() + } +} \ No newline at end of file diff --git a/src/Dynamic Data/dataContext.js b/src/Dynamic Data/dataContext.js new file mode 100644 index 0000000..ef24d01 --- /dev/null +++ b/src/Dynamic Data/dataContext.js @@ -0,0 +1,28 @@ +import React, { createContext, useEffect, useState } from 'react' +import { fetchCart, fetchProducts } from './DynamicData'; +export const productContext = createContext(); + +const DataContext = ({ children }) => { + const [products, setProducts] = useState(); + const [carts, setCarts] = useState(); + const [filteredProducts, setFilteredProducts] = useState(); + + useEffect(() => { + fetchProducts() + .then(res => { + setProducts(res.products); + setFilteredProducts(res.products) + }); + fetchCart() + .then(res => setCarts(res)) + }, []) + + return (<> + + {children} + + ) +} + + +export default DataContext; \ No newline at end of file diff --git a/src/Pages/Customers.js b/src/Pages/Customers.js new file mode 100644 index 0000000..cc0722e --- /dev/null +++ b/src/Pages/Customers.js @@ -0,0 +1,13 @@ +import { Container } from '@mui/material'; +import React, { useEffect } from 'react'; + + +const Customers = () => { + useEffect(() => { document.title = "Admin | Customers" }, []); + + return ( + Customers + ) +} + +export default Customers; \ No newline at end of file diff --git a/src/Pages/Dashboard/Cards.js b/src/Pages/Dashboard/Cards.js new file mode 100644 index 0000000..b6b1074 --- /dev/null +++ b/src/Pages/Dashboard/Cards.js @@ -0,0 +1,17 @@ +import React from 'react'; +import DashboardCard from './DashboardCard'; + +import { Stack } from '@mui/material'; +const Cards = ({ orders = 0, inventory = 0, customers = 0, revenue = 0 }) => { + + const cardsLog = [{ title: "Orders", value: orders }, { title: "Inventory", value: inventory.length }, { title: "Customers", value: customers }, { title: "Revenue", value: revenue.toLocaleString() }] + //const formattedNumber = number.toLocaleString("en-US"); + return ( + + {/* useFlexGap helps in wrap */} + {cardsLog.map((ele, index) => ())} + + ) +} + +export default Cards; \ No newline at end of file diff --git a/src/Pages/Dashboard/DashboardCard.js b/src/Pages/Dashboard/DashboardCard.js new file mode 100644 index 0000000..0c8f2e1 --- /dev/null +++ b/src/Pages/Dashboard/DashboardCard.js @@ -0,0 +1,30 @@ +import { Card, Typography, Stack, CardContent, Skeleton } from '@mui/material'; + +import CurrencyRupeeIcon from '@mui/icons-material/CurrencyRupee'; +import InventoryIcon from '@mui/icons-material/Inventory'; +import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; +import AccountCircleIcon from '@mui/icons-material/AccountCircle'; +const DashboardCard = ({ ele, index }) => { + return ( + + + + {index % 2 === 0 ? index === 0 ? : : index === 1 ? : } + + + {ele.title} + + {!ele.value || ele.value === "0" ? : + {ele.value} + + } + + + + + ) +} +export default DashboardCard; \ No newline at end of file diff --git a/src/Pages/Dashboard/DashboardTable.js b/src/Pages/Dashboard/DashboardTable.js new file mode 100644 index 0000000..3edca19 --- /dev/null +++ b/src/Pages/Dashboard/DashboardTable.js @@ -0,0 +1,59 @@ +import React, { useEffect, useState } from 'react' +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; +import Paper from '@mui/material/Paper'; + +const DashboardTable = ({ orders }) => { + const [row, setRow] = useState(null); + const [randomIndex, setRandomIndex] = useState(0); + + //Math.floor(Math.random() * arr.length) + useEffect(() => { + if (orders) { + // setRandomIndex(Math.floor(Math.random() * orders.carts.length)); + // setRow(orders.carts[randomIndex].products) + setRow(orders.slice(0, 5)); + } + }, [orders]) + + + + function BasicTable() { + return (<> + + + + + Title + Quantity + Price + + + + {row && + row.map((item) => ( + + {item.title} + {item.quantity} + {item.price} + + ))} + +
+
+ + ); + } + return ( + + ) +} + +export default DashboardTable; diff --git a/src/Pages/Dashboard/DiscountChart.js b/src/Pages/Dashboard/DiscountChart.js new file mode 100644 index 0000000..9a184ca --- /dev/null +++ b/src/Pages/Dashboard/DiscountChart.js @@ -0,0 +1,110 @@ +import React, { useState, useEffect } from 'react'; +import { Bar } from "react-chartjs-2"; +import { Box, Skeleton } from '@mui/material'; + +const PriceVsDiscount = ({ chartsData }) => { + const [revenueData, setRevenueData] = useState({ + labels: [], + datasets: [], + }); + const [loader, setLoader] = useState(true); + useEffect(() => { + if (chartsData) { + + // console.log("chartsData", chartsData) + const labels = chartsData.map((product) => { + return `User-${product.id}`; + }); + const discountData = chartsData.map((product) => { + let discountedValue = product.price * (1 - product.discountPercentage / 100); + return discountedValue; + }); + const PriceData = chartsData.map((product) => { + return product.price; + }); + + const dataSource = { + labels, + datasets: [ + { + label: "DiscountedPrice", + data: discountData, + backgroundColor: "rgba(255, 0, 0, 0.51)", + borderRadius: 10, + order: 0, + categoryPercentage: 0.75 + }, + { + label: "Price", + data: PriceData, + backgroundColor: "rgba(0, 0, 0, 0.41)", + borderRadius: 10, + order: 1, + categoryPercentage: 0.76 + }, + ], + }; + + setRevenueData(dataSource); + setLoader(false); + } + + }, [chartsData]); + + const options = { + responsive: true, + scales: { + x: { + stacked: true, + }, + y: { + beginAtZero: true, + }, + }, + legend: { + display: false + }, + } + + // const options = { + // responsive: true, + // interaction: { + // intersect: false, + // }, + // scales: { + // x: { + // stacked: true, + // }, + // y: { + // stacked: true, + // beginAtZero: true + + // } + // }, + // plugins: { + // legend: { + // position: "top", + // }, + // title: { + // display: false, + // text: "Order Revenue", + // }, + // }, + // }; + + return (<> {loader ? + < div style={{ paddingTop: '57%' } + } /> + : + + + + } + + + ) +} + +export default PriceVsDiscount; \ No newline at end of file diff --git a/src/Pages/Dashboard/RatingChart.js b/src/Pages/Dashboard/RatingChart.js new file mode 100644 index 0000000..2a69999 --- /dev/null +++ b/src/Pages/Dashboard/RatingChart.js @@ -0,0 +1,83 @@ +import React, { useState, useEffect } from 'react' +import { Pie, Scatter } from 'react-chartjs-2'; +import { Skeleton, Box } from '@mui/material'; + +const RatingChart = ({ chartsData }) => { + const [ratingData, setRatingData] = useState({ + labels: [], + datasets: [], + }); + const [loader, setLoader] = useState(true); + + useEffect(() => { + if (chartsData) { + // console.log("Rating", chartsData.products[0].rating) + + // const counts = {}; + // for (const num of arr) { + // counts[num] = counts[num] ? counts[num] + 1 : 1; //occurrence counter + // } + const counts = { "4.75 to 5": 0, "4.5 to 4.75": 0, "4.25 to 4.5": 0, "4 to 4.25": 0, "Below 4": 0 }; + for (const num of chartsData) { + if (num.rating <= 5 && num.rating >= 4.75) + counts["4.75 to 5"] = counts["4.75 to 5"] + 1; + else if (num.rating < 4.75 && num.rating >= 4.5) + counts["4.5 to 4.75"] = counts["4.5 to 4.75"] + 1; + else if (num.rating < 4.5 && num.rating >= 4.25) + counts["4.25 to 4.5"] = counts["4.25 to 4.5"] + 1; + else if (num.rating < 4.25 && num.rating >= 4) + counts["4 to 4.25"] = counts["4 to 4.25"] + 1; + else + counts["Below 3"] = counts["Below 3"] + 1; + + // counts[num.rating] = counts[num.rating] ? counts[num.rating] + 1 : 1; + } + + // const data = chartsData.products.map((ele) => { + // return { x: ele.rating, y: ele.rating }; //Scatter + // }); + const data = Object.values(counts); + const ratingLabels = Object.keys(counts); + // console.log("Rating", counts) + + const dataSource = { + labels: ratingLabels, + datasets: [ + { + label: 'Rating', + data: data, + backgroundColor: [ + 'rgba(255, 99, 132, 0.5)', + 'rgba(54, 162, 235, 0.5)', + 'rgba(255, 206, 86, 0.5)', + 'rgba(75, 192, 192, 0.5)', + 'rgba(153, 102, 255, 0.5)'], + }, + ], + }; + setRatingData(dataSource); + setLoader(false); + } + }, [chartsData]); + + const options = { + responsive: true, + circumference: 360 + }; + + return ( + <> {loader ? + +
+ : + + {/* */} + + } + + ) +} + +export default RatingChart; \ No newline at end of file diff --git a/src/Pages/Dashboard/RevenueChart.js b/src/Pages/Dashboard/RevenueChart.js new file mode 100644 index 0000000..0dc0da8 --- /dev/null +++ b/src/Pages/Dashboard/RevenueChart.js @@ -0,0 +1,79 @@ +import React, { useState, useEffect } from 'react' +import { Line } from 'react-chartjs-2'; +import { Skeleton, Box } from '@mui/material'; + +const RatingChart = ({ chartsData }) => { + const [revenueData, setRevenueData] = useState({ + labels: [], + datasets: [], + }); + const [loader, setLoader] = useState(true); + + useEffect(() => { + if (chartsData) { + // console.log("chartsData", chartsData) + const labels = chartsData.map((product) => { + return `User-${product.id}`; + }); + const data = chartsData.map((product) => { + return product.price; + }); + + const dataSource = { + labels, + datasets: [ + { + label: 'Order Revenue', + data: data, + fill: true, + borderColor: "rgb(255, 99, 132)", + backgroundColor: "rgba(255, 99, 132, 0.5)", + tension: 0.4, + pointStyle: "circle" + }, + ], + }; + + setRevenueData(dataSource); + setLoader(false); + } + }, [chartsData]); + + const options = { + type: "line", + responsive: true, + scales: { + y: { + beginAtZero: true + } + }, + plugins: { + legend: { + position: "top", + }, + title: { + display: false, + text: "Order Revenue", + }, + tooltip: { + titleColor: "#fff", + cornerRadius: 15 + } + }, + }; + + return ( + <> {loader ? + +
+ : + + + } + + ) +} + +export default RatingChart; \ No newline at end of file diff --git a/src/Pages/Dashboard/index.js b/src/Pages/Dashboard/index.js new file mode 100644 index 0000000..cb6cbd3 --- /dev/null +++ b/src/Pages/Dashboard/index.js @@ -0,0 +1,88 @@ +import React, { useEffect, useState, useContext } from 'react'; +import { Grid, Skeleton, Typography } from '@mui/material'; + +// import { fetchCart, fetchProducts } from '../../Dynamic Data/DynamicData'; +import { productContext } from '../../Dynamic Data/dataContext'; +import Cards from './Cards'; +import DashboardTable from './DashboardTable'; +import RevenueChart from './RevenueChart'; +import { + Chart as ChartJS, Title, Tooltip, Legend, //Common + + CategoryScale, LinearScale, //Line & Bar Chart + + BarElement,//Bar Chart + + PointElement, LineElement, Filler, //Line Chart & Area Chart + + ArcElement, //Pie Chart +} from "chart.js"; +import RatingChart from './RatingChart'; +import PriceVsDiscount from './DiscountChart'; + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend, + PointElement, LineElement, Filler, + ArcElement, +); + +const Dashboard = () => { + useEffect(() => { document.title = "Admin | Dashboard" }, []); + //destructure according to index[products, setProducts, carts, setCarts, filteredProducts, setFilteredProducts] + const [products, , , , filteredProducts, setFilteredProducts] = useContext(productContext); + + // const [carts, setCarts] = useState(); + // const [products, setProducts] = useState(); + const [orders, setOrders] = useState(0); + const [revenue, setRevenue] = useState(0); + const [loader, setLoader] = useState(true); + + useEffect(() => { + setLoader(true); + if (products) { + let revenue = filteredProducts.reduce((accumulator, object) => { + return accumulator + object.price; + }, 0); + setRevenue(revenue); + setOrders(products.length); + setLoader(false); + } + }, + // eslint-disable-next-line + [filteredProducts]); + console.log(products); + + return (<> + + + + + + Revenue + + + + Price VS DiscountedPrice + + + + <>Recent Orders + {loader ? +
+ : + + } + + + Product Rating + + + ) +} + +export default Dashboard; \ No newline at end of file diff --git a/src/Pages/Inventory/InventoryFilter.js b/src/Pages/Inventory/InventoryFilter.js new file mode 100644 index 0000000..e704b8f --- /dev/null +++ b/src/Pages/Inventory/InventoryFilter.js @@ -0,0 +1,52 @@ +import React, { useState, useContext, useEffect } from 'react' +import InputLabel from '@mui/material/InputLabel'; +import MenuItem from '@mui/material/MenuItem'; +import FormControl from '@mui/material/FormControl'; +import Select from '@mui/material/Select'; +import { productContext } from '../../Dynamic Data/dataContext'; +import { useNavigate } from 'react-router-dom'; + +const InventoryFilter = () => { + const [data, setData] = useState(''); + //destructure according to index[products, setProducts, carts, setCarts, filteredProducts, setFilteredProducts] + const [products, , , , filteredProducts, setFilteredProducts] = useContext(productContext); + const [category, setCategory] = useState([]); + const navigate = useNavigate(); + useEffect(() => { + //let unique = [...new Set(myArray)]; // unique Elements + setCategory([...new Set(products.map((ele) => ele.category))]); + }, []) + + useEffect(() => { + if (data === "") { + setFilteredProducts(products); + } + else { + setFilteredProducts(products.filter((ele) => ele.category === data)); + } + console.log(filteredProducts); + }, [data]) + + return ( + + Filter + + + ); +} + +export default InventoryFilter; \ No newline at end of file diff --git a/src/Pages/Inventory/InventoryTable.js b/src/Pages/Inventory/InventoryTable.js new file mode 100644 index 0000000..a8330a3 --- /dev/null +++ b/src/Pages/Inventory/InventoryTable.js @@ -0,0 +1,106 @@ +import React, { useContext, useEffect, useState } from 'react' +import { Box } from '@mui/material'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TablePagination from '@mui/material/TablePagination'; +import TableRow from '@mui/material/TableRow'; +import { productContext } from '../../Dynamic Data/dataContext'; + +const InventoryTable = () => { + //destructure according to index [products, setProducts, carts, setCarts, filteredProducts, setFilteredProducts] + const [, , , , filteredProducts,] = useContext(productContext) + const [rowData, setRowData] = useState(); + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(10); + + useEffect(() => { + if (filteredProducts) + setRowData(filteredProducts) + }, [filteredProducts]); + + const columns = [ + { id: 'id', label: 'Sr No.', width: 3 + "rem" }, + { id: 'title', label: 'Title', align: 'left', width: 7 + "rem" }, + { id: 'stock', label: 'Stock', align: 'center', width: 5 + "rem" }, + { + id: 'price', + label: 'Price', + width: 5 + "rem", + align: 'center', + format: (value) => value.toLocaleString(), + } + ]; + + const handleChangePage = (event, newPage) => { + if (event.target.getAttribute("data-testid") === "KeyboardArrowRightIcon") + setPage(newPage + 1); + else if (event.target.getAttribute("data-testid") === "KeyboardArrowLeftIcon") + setPage(newPage - 1); + else + setPage(newPage); + // console.log(event.target.getAttribute("data-testid"), newPage) + }; + + const handleChangeRowsPerPage = (event) => { + setRowsPerPage(+event.target.value); + setPage(0); + }; + + return (<>{rowData && <> + + + + + {columns.map((column) => ( + + {column.label} + + ))} + + + + {rowData + .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) + .map((row) => { + return ( + + {columns.map((column) => { + const value = row[column.id]; + return ( + + {column.format && typeof value === 'number' + ? column.format(value) + : value} + + ); + })} + + ); + })} + +
+
+ handleChangePage(e, page)} + onRowsPerPageChange={handleChangeRowsPerPage} + sx={{ + padding: 0, bgcolor: "lightcoral", margin: 0 + }} + /> + } + ); +} + +export default InventoryTable; \ No newline at end of file diff --git a/src/Pages/Inventory/index.js b/src/Pages/Inventory/index.js new file mode 100644 index 0000000..588b96e --- /dev/null +++ b/src/Pages/Inventory/index.js @@ -0,0 +1,35 @@ +import React, { useEffect, useContext } from 'react' + +import { Box, Container, Typography, Stack } from '@mui/material'; +import InventoryFilter from './InventoryFilter'; +import InventoryTable from './InventoryTable'; +import { useNavigate } from 'react-router-dom'; +import { productContext } from '../../Dynamic Data/dataContext'; + +const Inventory = () => { + //destructure according to index[products, setProducts, carts, setCarts, filteredProducts, setFilteredProducts] + const [products] = useContext(productContext); + const navigate = useNavigate(); + + + + useEffect(() => { + document.title = "Admin | Inventory"; + if (!products) { + navigate('/'); + } + }, []); + + return ( + {products && + + Inventory + + + + } + + ); +} + +export default Inventory; \ No newline at end of file diff --git a/src/Pages/Orders/index.js b/src/Pages/Orders/index.js new file mode 100644 index 0000000..7fbec85 --- /dev/null +++ b/src/Pages/Orders/index.js @@ -0,0 +1,52 @@ +import { Container } from '@mui/material'; +import React, { useState, useEffect } from 'react' +import { fetchCart, fetchProducts } from '../../Dynamic Data/DynamicData'; + +// import { productContext } from '../../Dynamic Data/dataContext'; + +const Orders = () => { + // const [products, setProducts, carts, setCarts] = useContext(productContext) + useEffect(() => { + document.title = "Admin | Orders"; + console.log(products, carts); + + }, []); + const [carts, setCarts] = useState(); + const [products, setProducts] = useState(); + const [orders, setOrders] = useState(0); + const [revenue, setRevenue] = useState(0); + const [loader, setLoader] = useState(true); + + useEffect(() => { + setTimeout(() => {// setTimeout used to test loader + fetchCart().then((res) => { + setCarts(res); + let orders = res.carts.reduce((accumulator, object) => { + // console.log(accumulator) + return accumulator + object.totalQuantity; + }, 0); + setOrders(orders); + + let revenue = res.carts.reduce((accumulator, object) => { + return accumulator + object.discountedTotal; + }, 0);; + setRevenue(revenue); + }); + fetchProducts().then((res) => { + setProducts(res); + // console.log("products", res,products); + }); + setLoader(false); + }, 500); + }, + // console.log("cart", carts, "products", products, "orders: ", orders, " inventory: ", products.total, " customers: ", carts.total, " revenue: ", revenue); + // eslint-disable-next-line + []); + + + return ( + Orders + ) +} + +export default Orders; \ No newline at end of file diff --git a/src/components/SideBar.js b/src/components/SideBar.js new file mode 100644 index 0000000..14ceeab --- /dev/null +++ b/src/components/SideBar.js @@ -0,0 +1,175 @@ +import { useState } from 'react'; +import { styled } from '@mui/material/styles'; +import Box from '@mui/material/Box'; +import MuiDrawer from '@mui/material/Drawer'; +import MuiAppBar from '@mui/material/AppBar'; +import Toolbar from '@mui/material/Toolbar'; +import List from '@mui/material/List'; +import CssBaseline from '@mui/material/CssBaseline'; +import Typography from '@mui/material/Typography'; +import Divider from '@mui/material/Divider'; +import IconButton from '@mui/material/IconButton'; +import MenuIcon from '@mui/icons-material/Menu'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import CloseIcon from '@mui/icons-material/Close'; + +import DashboardCustomizeIcon from '@mui/icons-material/DashboardCustomize'; +import InventoryIcon from '@mui/icons-material/Inventory'; +import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; +import AccountCircleIcon from '@mui/icons-material/AccountCircle'; + +import { Link, useLocation } from "react-router-dom"; +import { Stack } from '@mui/material'; +import Dashboard from '../Pages/Dashboard'; + +const drawerWidth = 180; + +const openedMixin = (theme) => ({ + width: drawerWidth, + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.enteringScreen, + }), + overflowX: 'hidden', +}); + +const closedMixin = (theme) => ({ + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + overflowX: 'hidden', + width: `calc(${theme.spacing(7)} + 1px)`, + [theme.breakpoints.up('xs')]: { + width: `calc(${theme.spacing(0)} + 1px)`, + }, [theme.breakpoints.up('md')]: { + width: `calc(${theme.spacing(7)} + 1px)`, + }, +}); + +const DrawerHeader = styled('div')(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + padding: theme.spacing(0, 1), + // necessary for content to be below app bar + ...theme.mixins.toolbar, +})); + +const AppBar = styled(MuiAppBar, { + shouldForwardProp: (prop) => prop !== 'open', +})(({ theme, open }) => ({ + zIndex: theme.zIndex.drawer + 1, + transition: theme.transitions.create(['width', 'margin'], { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + ...(open && { + marginLeft: drawerWidth, + width: `calc(100% - ${drawerWidth}px)`, + transition: theme.transitions.create(['width', 'margin'], { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.enteringScreen, + }), + }), +})); + +const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open' })( + ({ theme, open }) => ({ + width: drawerWidth, + flexShrink: 0, + whiteSpace: 'nowrap', + boxSizing: 'border-box', + ...(open && { + ...openedMixin(theme), + '& .MuiDrawer-paper': openedMixin(theme), + }), + ...(!open && { + ...closedMixin(theme), + '& .MuiDrawer-paper': closedMixin(theme), + }), + }), +); + +export default function MiniDrawer() { + const [open, setOpen] = useState(false); + const location = useLocation(); + let title = location.pathname.slice(1); + + const handleDrawerOpen = () => { + setOpen(true); + }; + + const handleDrawerClose = () => { + setOpen(false); + }; + + return ( + + + + + + {open ? : } + + + {title ? title : "Dashboard"} + + + + + + + Admin + + {open ? : } + + + + + + {['Dashboard', 'Inventory', 'Orders', 'Customers'].map((text, index) => + ( + + + + + {index % 2 === 0 ? index === 0 ? : : index === 1 ? : } + + + + + ) + )} + + + + + + + ); +} \ No newline at end of file diff --git a/src/index.css b/src/index.css index ec2585e..005eadf 100644 --- a/src/index.css +++ b/src/index.css @@ -1,13 +1,14 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + background-color: rgb(214, 233, 248); } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } diff --git a/src/index.js b/src/index.js index d563c0f..2cb1087 100644 --- a/src/index.js +++ b/src/index.js @@ -2,7 +2,6 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; -import reportWebVitals from './reportWebVitals'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( @@ -10,8 +9,3 @@ root.render( ); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 9dfc1c0..0000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js deleted file mode 100644 index 5253d3a..0000000 --- a/src/reportWebVitals.js +++ /dev/null @@ -1,13 +0,0 @@ -const reportWebVitals = onPerfEntry => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals; diff --git a/src/setupTests.js b/src/setupTests.js deleted file mode 100644 index 8f2609b..0000000 --- a/src/setupTests.js +++ /dev/null @@ -1,5 +0,0 @@ -// jest-dom adds custom jest matchers for asserting on DOM nodes. -// allows you to do things like: -// expect(element).toHaveTextContent(/react/i) -// learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom';