This commit is contained in:
client perkafean
2024-08-26 06:34:56 +00:00
parent 696ac38e33
commit 3a2e388a33
16 changed files with 1162 additions and 43 deletions

712
package-lock.json generated
View File

@@ -8,6 +8,9 @@
"name": "groovebrew-mockup", "name": "groovebrew-mockup",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@mui/x-charts": "^7.14.0",
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
@@ -1977,9 +1980,9 @@
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.24.7", "version": "7.25.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz",
"integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", "integrity": "sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==",
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.14.0" "regenerator-runtime": "^0.14.0"
}, },
@@ -2308,6 +2311,85 @@
"postcss-selector-parser": "^6.0.10" "postcss-selector-parser": "^6.0.10"
} }
}, },
"node_modules/@emotion/babel-plugin": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz",
"integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==",
"dependencies": {
"@babel/helper-module-imports": "^7.16.7",
"@babel/runtime": "^7.18.3",
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/serialize": "^1.2.0",
"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/@emotion/memoize": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ=="
},
"node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
},
"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/babel-plugin/node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
},
"node_modules/@emotion/cache": {
"version": "11.13.1",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz",
"integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==",
"dependencies": {
"@emotion/memoize": "^0.9.0",
"@emotion/sheet": "^1.4.0",
"@emotion/utils": "^1.4.0",
"@emotion/weak-memoize": "^0.4.0",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/cache/node_modules/@emotion/memoize": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ=="
},
"node_modules/@emotion/cache/node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
},
"node_modules/@emotion/hash": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g=="
},
"node_modules/@emotion/is-prop-valid": { "node_modules/@emotion/is-prop-valid": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz",
@@ -2321,11 +2403,114 @@
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
}, },
"node_modules/@emotion/react": {
"version": "11.13.3",
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz",
"integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==",
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.12.0",
"@emotion/cache": "^11.13.0",
"@emotion/serialize": "^1.3.1",
"@emotion/use-insertion-effect-with-fallbacks": "^1.1.0",
"@emotion/utils": "^1.4.0",
"@emotion/weak-memoize": "^0.4.0",
"hoist-non-react-statics": "^3.3.1"
},
"peerDependencies": {
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@emotion/serialize": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz",
"integrity": "sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA==",
"dependencies": {
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/unitless": "^0.10.0",
"@emotion/utils": "^1.4.0",
"csstype": "^3.0.2"
}
},
"node_modules/@emotion/serialize/node_modules/@emotion/memoize": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ=="
},
"node_modules/@emotion/serialize/node_modules/@emotion/unitless": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg=="
},
"node_modules/@emotion/sheet": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg=="
},
"node_modules/@emotion/styled": {
"version": "11.13.0",
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz",
"integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==",
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.12.0",
"@emotion/is-prop-valid": "^1.3.0",
"@emotion/serialize": "^1.3.0",
"@emotion/use-insertion-effect-with-fallbacks": "^1.1.0",
"@emotion/utils": "^1.4.0"
},
"peerDependencies": {
"@emotion/react": "^11.0.0-rc.0",
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@emotion/styled/node_modules/@emotion/is-prop-valid": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz",
"integrity": "sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==",
"dependencies": {
"@emotion/memoize": "^0.9.0"
}
},
"node_modules/@emotion/styled/node_modules/@emotion/memoize": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ=="
},
"node_modules/@emotion/unitless": { "node_modules/@emotion/unitless": {
"version": "0.8.1", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz",
"integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ=="
}, },
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz",
"integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==",
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@emotion/utils": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz",
"integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ=="
},
"node_modules/@emotion/weak-memoize": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg=="
},
"node_modules/@eslint-community/eslint-utils": { "node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@@ -3231,6 +3416,265 @@
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz",
"integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw=="
}, },
"node_modules/@mui/core-downloads-tracker": {
"version": "5.16.7",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz",
"integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
}
},
"node_modules/@mui/material": {
"version": "5.16.7",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz",
"integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/core-downloads-tracker": "^5.16.7",
"@mui/system": "^5.16.7",
"@mui/types": "^7.2.15",
"@mui/utils": "^5.16.6",
"@popperjs/core": "^2.11.8",
"@types/react-transition-group": "^4.4.10",
"clsx": "^2.1.0",
"csstype": "^3.1.3",
"prop-types": "^15.8.1",
"react-is": "^18.3.1",
"react-transition-group": "^4.4.5"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"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.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
"peer": true
},
"node_modules/@mui/private-theming": {
"version": "5.16.6",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz",
"integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/utils": "^5.16.6",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"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.16.6",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz",
"integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@emotion/cache": "^11.11.0",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"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.16.7",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz",
"integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/private-theming": "^5.16.6",
"@mui/styled-engine": "^5.16.6",
"@mui/types": "^7.2.15",
"@mui/utils": "^5.16.6",
"clsx": "^2.1.0",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"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.15",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz",
"integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==",
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/utils": {
"version": "5.16.6",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz",
"integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/types": "^7.2.15",
"@types/prop-types": "^15.7.12",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-is": "^18.3.1"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0",
"react": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/utils/node_modules/react-is": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
},
"node_modules/@mui/x-charts": {
"version": "7.14.0",
"resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.14.0.tgz",
"integrity": "sha512-yjBEGk9fl7rMnCaTqibQEf2Dq8oVMzMVDkEXOztJbb8XG+iC/EtRPOWRahgFVi5xitiKR+lLJ/ezBWzuYK739A==",
"dependencies": {
"@babel/runtime": "^7.25.0",
"@mui/system": "^5.16.7",
"@mui/utils": "^5.16.6",
"@mui/x-charts-vendor": "7.14.0",
"@react-spring/rafz": "^9.7.4",
"@react-spring/web": "^9.7.4",
"clsx": "^2.1.1",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@mui/material": "^5.15.14",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
}
}
},
"node_modules/@mui/x-charts-vendor": {
"version": "7.14.0",
"resolved": "https://registry.npmjs.org/@mui/x-charts-vendor/-/x-charts-vendor-7.14.0.tgz",
"integrity": "sha512-hhEwqQ5Gt2uEFCIna7OPycyu/CzVlywmH5SIX9O3Rxe/y0muLhafEX2ooOQpopcrgGPmP+2/zTf7cssXPiMmAQ==",
"dependencies": {
"@babel/runtime": "^7.25.0",
"@types/d3-color": "^3.1.3",
"@types/d3-delaunay": "^6.0.4",
"@types/d3-interpolate": "^3.0.4",
"@types/d3-scale": "^4.0.8",
"@types/d3-shape": "^3.1.6",
"@types/d3-time": "^3.0.3",
"d3-color": "^3.1.0",
"d3-delaunay": "^6.0.4",
"d3-interpolate": "^3.0.1",
"d3-scale": "^4.0.2",
"d3-shape": "^3.2.0",
"d3-time": "^3.1.0",
"delaunator": "^5.0.1",
"robust-predicates": "^3.0.2"
}
},
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1", "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", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -3370,6 +3814,72 @@
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
} }
}, },
"node_modules/@react-spring/animated": {
"version": "9.7.4",
"resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.4.tgz",
"integrity": "sha512-7As+8Pty2QlemJ9O5ecsuPKjmO0NKvmVkRR1n6mEotFgWar8FKuQt2xgxz3RTgxcccghpx1YdS1FCdElQNexmQ==",
"dependencies": {
"@react-spring/shared": "~9.7.4",
"@react-spring/types": "~9.7.4"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@react-spring/core": {
"version": "9.7.4",
"resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.4.tgz",
"integrity": "sha512-GzjA44niEJBFUe9jN3zubRDDDP2E4tBlhNlSIkTChiNf9p4ZQlgXBg50qbXfSXHQPHak/ExYxwhipKVsQ/sUTw==",
"dependencies": {
"@react-spring/animated": "~9.7.4",
"@react-spring/shared": "~9.7.4",
"@react-spring/types": "~9.7.4"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/react-spring/donate"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@react-spring/rafz": {
"version": "9.7.4",
"resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.4.tgz",
"integrity": "sha512-mqDI6rW0Ca8IdryOMiXRhMtVGiEGLIO89vIOyFQXRIwwIMX30HLya24g9z4olDvFyeDW3+kibiKwtZnA4xhldA=="
},
"node_modules/@react-spring/shared": {
"version": "9.7.4",
"resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.4.tgz",
"integrity": "sha512-bEPI7cQp94dOtCFSEYpxvLxj0+xQfB5r9Ru1h8OMycsIq7zFZon1G0sHrBLaLQIWeMCllc4tVDYRTLIRv70C8w==",
"dependencies": {
"@react-spring/rafz": "~9.7.4",
"@react-spring/types": "~9.7.4"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@react-spring/types": {
"version": "9.7.4",
"resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.4.tgz",
"integrity": "sha512-iQVztO09ZVfsletMiY+DpT/JRiBntdsdJ4uqk3UJFhrhS8mIC9ZOZbmfGSRs/kdbNPQkVyzucceDicQ/3Mlj9g=="
},
"node_modules/@react-spring/web": {
"version": "9.7.4",
"resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.4.tgz",
"integrity": "sha512-UMvCZp7I5HCVIleSa4BwbNxynqvj+mJjG2m20VO2yPoi2pnCYANy58flvz9v/YcXTAvsmL655FV3pm5fbr6akA==",
"dependencies": {
"@react-spring/animated": "~9.7.4",
"@react-spring/core": "~9.7.4",
"@react-spring/shared": "~9.7.4",
"@react-spring/types": "~9.7.4"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@remix-run/router": { "node_modules/@remix-run/router": {
"version": "1.17.0", "version": "1.17.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.0.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.0.tgz",
@@ -4134,6 +4644,50 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/d3-color": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
"integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="
},
"node_modules/@types/d3-delaunay": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
"integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw=="
},
"node_modules/@types/d3-interpolate": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
"integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
"dependencies": {
"@types/d3-color": "*"
}
},
"node_modules/@types/d3-path": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz",
"integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ=="
},
"node_modules/@types/d3-scale": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz",
"integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==",
"dependencies": {
"@types/d3-time": "*"
}
},
"node_modules/@types/d3-shape": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz",
"integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==",
"dependencies": {
"@types/d3-path": "*"
}
},
"node_modules/@types/d3-time": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz",
"integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw=="
},
"node_modules/@types/eslint": { "node_modules/@types/eslint": {
"version": "8.56.10", "version": "8.56.10",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
@@ -6296,6 +6850,14 @@
"wrap-ansi": "^7.0.0" "wrap-ansi": "^7.0.0"
} }
}, },
"node_modules/clsx": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
"engines": {
"node": ">=6"
}
},
"node_modules/co": { "node_modules/co": {
"version": "4.6.0", "version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -6933,6 +7495,111 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
}, },
"node_modules/d3-array": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
"integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
"dependencies": {
"internmap": "1 - 2"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-delaunay": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
"integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
"dependencies": {
"delaunator": "5"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-format": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
"integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
"dependencies": {
"d3-color": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-path": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
"integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-scale": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
"integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
"dependencies": {
"d3-array": "2.10.0 - 3",
"d3-format": "1 - 3",
"d3-interpolate": "1.2.0 - 3",
"d3-time": "2.1.1 - 3",
"d3-time-format": "2 - 4"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-shape": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
"integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
"dependencies": {
"d3-path": "^3.1.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-time": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
"integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
"dependencies": {
"d3-array": "2 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-time-format": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
"integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
"dependencies": {
"d3-time": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/damerau-levenshtein": { "node_modules/damerau-levenshtein": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@@ -7120,6 +7787,14 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/delaunator": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
"integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
"dependencies": {
"robust-predicates": "^3.0.2"
}
},
"node_modules/delayed-stream": { "node_modules/delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -8727,6 +9402,11 @@
"url": "https://github.com/avajs/find-cache-dir?sponsor=1" "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": { "node_modules/find-up": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -9390,6 +10070,19 @@
"he": "bin/he" "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": { "node_modules/hoopy": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
@@ -9792,6 +10485,14 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/internmap": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
"integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
"engines": {
"node": ">=12"
}
},
"node_modules/invariant": { "node_modules/invariant": {
"version": "2.2.4", "version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -15828,6 +16529,11 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/robust-predicates": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
},
"node_modules/rollup": { "node_modules/rollup": {
"version": "2.79.1", "version": "2.79.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",

View File

@@ -3,6 +3,9 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@mui/x-charts": "^7.14.0",
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",

View File

@@ -114,7 +114,7 @@ export default function Footer({
</span> </span>
{table.length == 0 && ( {table.length == 0 && (
<img <img
src="https://static-00.iconduck.com/assets.00/qr-scan-icon-2048x2048-aeh36n7y.png" src="https://i.ibb.co.com/Pt2s8N8/qr-scan-icon-2048x2048-aeh36n7y.png"
alt="QR Code" alt="QR Code"
className={styles.qrIcon} className={styles.qrIcon}
/> />

View File

@@ -1,3 +1,6 @@
.footerContainer {
margin-top: 40px;
}
.footer-rect { .footer-rect {
height: 75px; height: 75px;
background-color: #fff; background-color: #fff;

View File

@@ -284,7 +284,7 @@ const Header = ({
<Title>{HeaderText}</Title> <Title>{HeaderText}</Title>
<div style={{ visibility: showProfile ? "visible" : "hidden" }}> <div style={{ visibility: showProfile ? "visible" : "hidden" }}>
<ProfileImage <ProfileImage
src="https://static-00.iconduck.com/assets.00/profile-major-icon-1024x1024-9rtgyx30.png" src="https://i.ibb.co.com/fpg1v8J/profile-major-icon-1024x1024-9rtgyx30.png"
alt="Profile" alt="Profile"
onClick={handleImageClick} onClick={handleImageClick}
animate={showRectangle && animate} animate={showRectangle && animate}
@@ -349,6 +349,8 @@ const Header = ({
<Child onClick={() => setModal("payment_option")}> <Child onClick={() => setModal("payment_option")}>
payment options payment options
</Child> </Child>
<Child onClick={() => setModal("reports")}>reports</Child>
</Child> </Child>
</> </>
)} )}
@@ -385,6 +387,8 @@ const Header = ({
))} ))}
</Child> </Child>
)} )}
<Child onClick={() => setModal("reports")}>reports</Child>
</Child> </Child>
)} )}
{user.username !== undefined && ( {user.username !== undefined && (

View File

@@ -10,6 +10,7 @@ import Transaction_success from "../pages/Transaction_success";
import Transaction_failed from "../pages/Transaction_failed"; import Transaction_failed from "../pages/Transaction_failed";
import MaterialList from "../pages/MaterialList.js"; import MaterialList from "../pages/MaterialList.js";
import MaterialMutationsPage from "../pages/MaterialMutationsPage.js"; import MaterialMutationsPage from "../pages/MaterialMutationsPage.js";
import Reports from "../pages/Reports.js";
const Modal = ({ shop, isOpen, onClose, modalContent }) => { const Modal = ({ shop, isOpen, onClose, modalContent }) => {
if (!isOpen) return null; if (!isOpen) return null;
@@ -51,6 +52,9 @@ const Modal = ({ shop, isOpen, onClose, modalContent }) => {
{modalContent === "update_stock" && ( {modalContent === "update_stock" && (
<MaterialMutationsPage cafeId={shop.cafeId} /> <MaterialMutationsPage cafeId={shop.cafeId} />
)} )}
{modalContent === "reports" && (
<Reports cafeId={shop.cafeId} />
)}
</div> </div>
</div> </div>
); );

View File

@@ -90,8 +90,8 @@
} }
.expandable-container.expanded { .expandable-container.expanded {
-ms-overflow-style: none; /* IE and Edge */ -ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */ scrollbar-width: none; /* Firefox */
position: relative; position: relative;
max-height: 400px; max-height: 400px;
/* Adjust the max-height as needed */ /* Adjust the max-height as needed */
@@ -101,12 +101,11 @@
.expand-button { .expand-button {
font-size: 20px; font-size: 20px;
padding-bottom: 10px;
position: relative; position: relative;
left: 0; left: 0;
right: 0; right: 0;
height: 25px;
background-color: rgb(108, 255, 128); background-color: rgb(108, 255, 128);
/* background-color: rgb(218 163 99); */
border-radius: 0 0 15px 15px; border-radius: 0 0 15px 15px;
/* Rounded corners at the bottom */ /* Rounded corners at the bottom */
cursor: pointer; cursor: pointer;
@@ -116,7 +115,9 @@
} }
.expand-button h5 { .expand-button h5 {
font-weight: 500;
margin-top: 0px; margin-top: 0px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.36);
} }
.expand-button:hover { .expand-button:hover {

View File

@@ -1,5 +1,5 @@
// src/config.js // src/config.js
const API_BASE_URL = "https://2jtmkn-5000.csb.app"; // Replace with your actual backend URL const API_BASE_URL = "https://8h8rx8-5000.csb.app"; // Replace with your actual backend URL
export default API_BASE_URL; export default API_BASE_URL;

View File

@@ -28,7 +28,7 @@ export async function getOwnedCafes(userId) {
} }
} }
export async function createCafe(userId) { export async function createCafe(cafeName) {
try { try {
const response = await fetch(`${API_BASE_URL}/cafe/create-cafe`, { const response = await fetch(`${API_BASE_URL}/cafe/create-cafe`, {
method: "POST", method: "POST",
@@ -36,7 +36,8 @@ export async function createCafe(userId) {
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: `Bearer ${getAuthToken()}`, Authorization: `Bearer ${getAuthToken()}`,
}, },
body: JSON.stringify({ ownerId: userId }), body: JSON.stringify({
name: cafeName }),
}); });
if (!response.ok) { if (!response.ok) {

View File

@@ -2,21 +2,16 @@ import API_BASE_URL from "../config.js";
// Function to retrieve the authentication token from localStorage // Function to retrieve the authentication token from localStorage
function getAuthToken() { function getAuthToken() {
if (localStorage.getItem("auth")) return localStorage.getItem("auth"); return localStorage.getItem("auth") || null;
return null;
} }
// Helper function to get headers with authentication token // Helper function to get headers with authentication token
const getHeaders = (method = "GET", body = null) => { const getHeaders = () => {
const headers = {
Authorization: `Bearer ${getAuthToken()}`,
"Content-Type": "application/json",
};
return { return {
method, headers: {
headers, Authorization: `Bearer ${getAuthToken()}`,
body: body ? JSON.stringify(body) : null, "Content-Type": "application/json",
},
}; };
}; };
@@ -25,7 +20,14 @@ export const createMaterialMutation = async (materialId, data) => {
try { try {
const response = await fetch( const response = await fetch(
`${API_BASE_URL}/mutation/create/${materialId}`, `${API_BASE_URL}/mutation/create/${materialId}`,
getHeaders("POST", data) {
...getHeaders(),
method: "POST",
body: JSON.stringify({
newStock: data.get("newStock"),
reason: data.get("reason"),
}),
}
); );
if (!response.ok) throw new Error("Failed to create material mutation."); if (!response.ok) throw new Error("Failed to create material mutation.");
return await response.json(); return await response.json();
@@ -40,7 +42,10 @@ export const getMaterialMutations = async (cafeId) => {
try { try {
const response = await fetch( const response = await fetch(
`${API_BASE_URL}/mutation/get-material-mutations/${cafeId}`, `${API_BASE_URL}/mutation/get-material-mutations/${cafeId}`,
getHeaders() {
...getHeaders(),
method: "GET",
}
); );
if (!response.ok) throw new Error("Failed to retrieve material mutations."); if (!response.ok) throw new Error("Failed to retrieve material mutations.");
return await response.json(); return await response.json();
@@ -55,7 +60,10 @@ export const getMaterialMutationById = async (mutationId) => {
try { try {
const response = await fetch( const response = await fetch(
`${API_BASE_URL}/mutation/get-material-mutation/${mutationId}`, `${API_BASE_URL}/mutation/get-material-mutation/${mutationId}`,
getHeaders() {
...getHeaders(),
method: "GET",
}
); );
if (!response.ok) throw new Error("Failed to retrieve material mutation."); if (!response.ok) throw new Error("Failed to retrieve material mutation.");
return await response.json(); return await response.json();
@@ -70,7 +78,10 @@ export const getMaterialMutationsByMaterialId = async (materialId) => {
try { try {
const response = await fetch( const response = await fetch(
`${API_BASE_URL}/mutation/get-material-mutations-by-material/${materialId}`, `${API_BASE_URL}/mutation/get-material-mutations-by-material/${materialId}`,
getHeaders() {
...getHeaders(),
method: "GET",
}
); );
if (!response.ok) if (!response.ok)
throw new Error("Failed to retrieve material mutations by material ID."); throw new Error("Failed to retrieve material mutations by material ID.");

View File

@@ -288,3 +288,39 @@ export const handlePaymentFromGuestDevice = async (
return false; return false;
} }
}; };
// Function to retrieve the authentication token from localStorage
function getAuthToken() {
return localStorage.getItem("auth");
}
// Helper function to get headers with authentication token
const getHeaders = (method = "GET") => {
const headers = {
Authorization: `Bearer ${getAuthToken()}`,
};
// No content-type header needed for FormData; fetch will handle it automatically
if (method !== "POST" && method !== "PUT") {
return { method, headers };
}
return {
method,
headers,
};
};
export const getFavourite = async (cafeId) => {
const response = await fetch(
`${API_BASE_URL}/transaction/get-favourite/${cafeId}`,
getHeaders()
);
return response.json();
};
export const getAnalytics = async (cafeId) => {
const response = await fetch(
`${API_BASE_URL}/transaction/get-analytics/${cafeId}`,
getHeaders()
);
return response.json();
};

View File

@@ -0,0 +1,62 @@
import React from "react";
const CircularDiagram = ({ segments }) => {
const radius = 100; // Radius of the circle
const strokeWidth = 30; // Width of each portion
const circumference = 2 * Math.PI * (radius - strokeWidth / 2);
// Calculate total value to be displayed
const totalSold = segments.reduce((sum, segment) => sum + segment.value, 0);
let startOffset = 0; // Initial offset for each segment
const svgStyles = {
display: "block",
margin: "0 auto",
};
return (
<svg
width={radius * 2}
height={radius * 2}
viewBox={`0 0 ${radius * 2} ${radius * 2}`}
style={svgStyles}
>
<circle
cx={radius}
cy={radius}
r={radius - strokeWidth / 2}
stroke="#eee"
strokeWidth={strokeWidth}
fill="none"
/>
{segments.map((segment, index) => {
const { value, color } = segment;
const segmentLength = (circumference * value) / totalSold;
const strokeDashoffset = circumference - startOffset;
startOffset += segmentLength;
return (
<circle
key={index}
cx={radius}
cy={radius}
r={radius - strokeWidth / 2}
stroke={color}
strokeWidth={strokeWidth}
fill="none"
strokeDasharray={`${segmentLength} ${
circumference - segmentLength
}`}
strokeDashoffset={strokeDashoffset}
strokeLinecap="round" // Rounds the edges of each segment
transform={`rotate(-90 ${radius} ${radius})`}
/>
);
})}
</svg>
);
};
export default CircularDiagram;

View File

@@ -113,7 +113,7 @@ const Dashboard = ({ user, setModal }) => {
className={styles.rectangle} className={styles.rectangle}
onClick={() => setIsCreating(true)} onClick={() => setIsCreating(true)}
> >
Create Cafe +
</div> </div>
)} )}
</div> </div>

View File

@@ -23,6 +23,7 @@ const MaterialList = ({ cafeId }) => {
const [selectedMaterialId, setSelectedMaterialId] = useState(null); const [selectedMaterialId, setSelectedMaterialId] = useState(null);
const [currentQuantity, setCurrentQuantity] = useState(0); const [currentQuantity, setCurrentQuantity] = useState(0);
const [quantityChange, setQuantityChange] = useState(0); const [quantityChange, setQuantityChange] = useState(0);
const [sortOrder, setSortOrder] = useState("desc");
useEffect(() => { useEffect(() => {
const fetchMaterials = async () => { const fetchMaterials = async () => {
@@ -63,7 +64,7 @@ const MaterialList = ({ cafeId }) => {
if (materialMutations.length > 0) { if (materialMutations.length > 0) {
const latestMutation = materialMutations.reduce( const latestMutation = materialMutations.reduce(
(latest, current) => (latest, current) =>
new Date(current.timestamp) > new Date(latest.timestamp) new Date(current.createdAt) > new Date(latest.createdAt)
? current ? current
: latest, : latest,
materialMutations[0] materialMutations[0]
@@ -75,10 +76,24 @@ const MaterialList = ({ cafeId }) => {
} }
}, [selectedMaterialId, mutations]); }, [selectedMaterialId, mutations]);
const handleSortChange = (e) => {
setSortOrder(e.target.value);
};
const filteredMutations = selectedMaterialId const filteredMutations = selectedMaterialId
? mutations.filter((mutation) => mutation.materialId === selectedMaterialId) ? mutations.filter((mutation) => mutation.materialId === selectedMaterialId)
: []; : [];
const sortedMutations = filteredMutations
.filter((mutation) => mutation.materialId === selectedMaterialId)
.sort((a, b) => {
if (sortOrder === "asc") {
return new Date(a.createdAt) - new Date(b.createdAt);
} else {
return new Date(b.createdAt) - new Date(a.createdAt);
}
});
const handleCreateMaterial = async (e) => { const handleCreateMaterial = async (e) => {
e.preventDefault(); e.preventDefault();
setLoading(true); setLoading(true);
@@ -166,11 +181,10 @@ const MaterialList = ({ cafeId }) => {
try { try {
const newStock = currentQuantity + quantityChange; const newStock = currentQuantity + quantityChange;
const formData = new FormData(); const formData = new FormData();
formData.append("materialId", selectedMaterialId);
formData.append("newStock", newStock); formData.append("newStock", newStock);
formData.append("reason", "Stock update"); formData.append("reason", "Stock update");
await createMaterialMutation(cafeId, formData); await createMaterialMutation(selectedMaterialId, formData);
setQuantityChange(0); setQuantityChange(0);
const updatedMutations = await getMaterialMutations(cafeId); const updatedMutations = await getMaterialMutations(cafeId);
setMutations(updatedMutations); setMutations(updatedMutations);
@@ -188,6 +202,10 @@ const MaterialList = ({ cafeId }) => {
const currentMaterial = materials.find( const currentMaterial = materials.find(
(material) => material.materialId === selectedMaterialId (material) => material.materialId === selectedMaterialId
); );
const formatDate = (timestamp) => {
const date = new Date(timestamp);
return date.toLocaleString();
};
return ( return (
<div style={styles.container}> <div style={styles.container}>
@@ -299,7 +317,7 @@ const MaterialList = ({ cafeId }) => {
- -
</button> </button>
<button style={styles.quantityDisplay}> <button style={styles.quantityDisplay}>
{currentQuantity + quantityChange} {currentQuantity + quantityChange}
</button> </button>
<button <button
onClick={() => handleQuantityChange(1)} onClick={() => handleQuantityChange(1)}
@@ -346,15 +364,27 @@ const MaterialList = ({ cafeId }) => {
</div> </div>
)} )}
<div style={styles.sortContainer}>
<label htmlFor="sortOrder">Sort by : </label>
<select
id="sortOrder"
value={sortOrder}
onChange={handleSortChange}
style={styles.sortSelect}
>
<option value="desc">latest</option>
<option value="asc">oldest</option>
</select>
</div>
{selectedMaterialId && !loading && ( {selectedMaterialId && !loading && (
<div style={styles.mutationContainer}> <div style={styles.mutationContainer}>
{filteredMutations.length > 0 ? ( {sortedMutations.length > 0 ? (
filteredMutations.map((mutation) => ( sortedMutations.map((mutation) => (
<div key={mutation.id} style={styles.mutationCard}> <div key={mutation.id} style={styles.mutationCard}>
<h4 style={styles.mutationTitle}>Mutation ID: {mutation.id}</h4> <h4 style={styles.mutationTitle}>{formatDate(mutation.createdAt)}</h4>
<p>Details: {mutation.reason}</p> <p>Details: {mutation.reason}</p>
<p>dari {mutation.oldStock}</p> <p>stok {mutation.newStock}</p>
<p>ke {mutation.newStock}</p>
</div> </div>
)) ))
) : ( ) : (

259
src/pages/Reports.js Normal file
View File

@@ -0,0 +1,259 @@
import React, { useEffect, useState } from "react";
import { ThreeDots } from "react-loader-spinner";
import { getFavourite, getAnalytics } from "../helpers/transactionHelpers.js";
import CircularDiagram from "./CircularDiagram";
import styles from "./Transactions.module.css";
const RoundedRectangle = ({ bgColor, title, value, percentage }) => {
const containerStyle = {
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
justifyContent: "center",
width: "calc(100% / 2 - 10px)",
maxWidth: "250px",
height: "auto",
borderRadius: "15px",
padding: "20px",
margin: "5px",
textAlign: "left",
fontFamily: "Arial, sans-serif",
boxSizing: "border-box",
};
const titleStyle = {
fontWeight: "bold",
marginBottom: "10px",
width: "100%",
};
const valueAndPercentageContainerStyle = {
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
};
const valueStyle = {
fontSize: "20px",
fontWeight: "bold",
flex: "1",
textAlign: "left",
};
const percentageStyle = {
fontSize: "16px",
display: "flex",
alignItems: "center",
textAlign: "right",
};
const arrowStyle = {
marginLeft: "5px",
};
return (
<div
style={{
...containerStyle,
backgroundColor: bgColor,
}}
>
<div style={titleStyle}>{title}</div>
<div style={valueAndPercentageContainerStyle}>
<div style={valueStyle}>{value}</div>
<div
style={{
...percentageStyle,
color: percentage > 0 ? "#007bff" : "red",
}}
>
{percentage}%
<span style={arrowStyle}>{percentage > 0 ? "↗" : "↘"}</span>
</div>
</div>
</div>
);
};
const App = ({ cafeId }) => {
const [favouriteItems, setFavouriteItems] = useState([]);
const [analytics, setAnalytics] = useState({});
const [loading, setLoading] = useState(true);
const [filter, setFilter] = useState("monthly"); // Default filter is 'monthly'
const [colors, setColors] = useState([]);
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const items = await getFavourite(cafeId);
const analyticsData = await getAnalytics(cafeId);
if (items) setFavouriteItems(items);
if (analyticsData) setAnalytics(analyticsData);
} catch (error) {
console.error("Error fetching data:", error);
} finally {
setLoading(false);
}
};
fetchData();
}, [cafeId]);
useEffect(() => {
const getRandomColor = () => {
const letters = "0123456789ABCDEF";
let color = "#";
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
const r = parseInt(color.substring(1, 3), 16);
const g = parseInt(color.substring(3, 5), 16);
const b = parseInt(color.substring(5, 7), 16);
return `rgba(${r}, ${g}, ${b}, 1)`;
};
const colors = favouriteItems[filter]?.map(() => getRandomColor()) || [];
setColors(colors);
}, [favouriteItems, filter]);
if (loading)
return (
<div className="Loader">
<div className="LoaderChild">
<ThreeDots />
</div>
</div>
);
const [sold, percentage] = analytics[filter] || [0, 0];
const filteredItems = favouriteItems[filter] || [];
const totalSold = filteredItems.reduce((sum, item) => sum + item.sold, 0);
const segments = filteredItems.map((item, index) => ({
value: item.sold,
color: colors[index] || "#cccccc",
}));
return (
<div className={styles.Transactions} style={{ backgroundColor: "#cfcfcf" }}>
<h2 className={styles["Transactions-title"]}>Reports</h2>
<div style={{ marginTop: "30px", textAlign: "center" }}>
<div>
<label>
<input
type="radio"
name="filter"
value="daily"
checked={filter === "daily"}
onChange={() => setFilter("daily")}
/>
Daily
</label>
<label style={{ marginLeft: "10px" }}>
<input
type="radio"
name="filter"
value="weekly"
checked={filter === "weekly"}
onChange={() => setFilter("weekly")}
/>
Weekly
</label>
<label style={{ marginLeft: "10px" }}>
<input
type="radio"
name="filter"
value="monthly"
checked={filter === "monthly"}
onChange={() => setFilter("monthly")}
/>
Monthly
</label>
<label style={{ marginLeft: "10px" }}>
<input
type="radio"
name="filter"
value="yearly"
checked={filter === "yearly"}
onChange={() => setFilter("yearly")}
/>
Yearly
</label>
</div>
<div
style={{
display: "flex",
flexWrap: "wrap",
justifyContent: "center",
marginTop: "20px",
padding: "20px",
}}
>
<RoundedRectangle
bgColor="#E3F5FF"
title="Transactions"
value={sold}
percentage={percentage}
/>
{filteredItems[0]?.Item != undefined && (
<RoundedRectangle
bgColor="#E5ECF6"
title={filteredItems[0]?.Item.name}
value={filteredItems[0]?.sold}
percentage={filteredItems[0]?.percentageByPreviousPeriod}
/>
)}
{filteredItems[0]?.Item == undefined && (
<RoundedRectangle bgColor="#E5ECF6" value={"No item"} />
)}
<RoundedRectangle
bgColor="#E5ECF6"
title="Transactions"
value={sold}
percentage={percentage}
/>
<RoundedRectangle
bgColor="#E3F5FF"
title="Transactions"
value={sold}
percentage={percentage}
/>
</div>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "20px",
}}
>
<div style={{ flex: 1 }}>
<CircularDiagram segments={segments} />
</div>
<div style={{ flex: 1, marginLeft: "20px" }}>
{filteredItems.map((item, index) => (
<h6
key={item.itemId}
style={{
textAlign: "left",
color: colors[index],
margin: "5px 0",
}}
>
{item.Item.name}: {item.sold}
</h6>
))}
</div>
</div>
</div>
</div>
);
};
export default App;

View File

@@ -3,7 +3,7 @@ import { useNavigate } from "react-router-dom";
import { QrReader } from "react-qr-reader"; // Import QrReader as named import import { QrReader } from "react-qr-reader"; // Import QrReader as named import
import styles from "./GuestSideLogin.module.css"; // Import module CSS file for styles import styles from "./GuestSideLogin.module.css"; // Import module CSS file for styles
import { getLocalStorage } from "../helpers/localStorageHelpers"; import { getTableByCode } from "../helpers/tableHelper";
const GuestSideLogin = ({ socket }) => { const GuestSideLogin = ({ socket }) => {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -15,9 +15,8 @@ const GuestSideLogin = ({ socket }) => {
navigate("/" + shopId); navigate("/" + shopId);
}); });
const setLoginGuestSide = () => { const setLoginGuestSide = async () => {
const token = getLocalStorage("auth"); window.location.href = qrCode;
socket.emit("read_qrCode", { qrCode, token });
}; };
// Function to handle QR code scan // Function to handle QR code scan
@@ -39,7 +38,7 @@ const GuestSideLogin = ({ socket }) => {
}; };
useEffect(() => { useEffect(() => {
if (qrCode.length === 11) { if (qrCode.length === 40) {
const timer = setTimeout(() => { const timer = setTimeout(() => {
setLoginGuestSide(); setLoginGuestSide();
}, 1000); // Delay of 1 second (1000 milliseconds) }, 1000); // Delay of 1 second (1000 milliseconds)