diff --git a/egovframe-template-simple-react-contribution/package-lock.json b/egovframe-template-simple-react-contribution/package-lock.json index 06b541f..c437d82 100644 --- a/egovframe-template-simple-react-contribution/package-lock.json +++ b/egovframe-template-simple-react-contribution/package-lock.json @@ -8,7 +8,12 @@ "name": "template.web.boot.simple.homepage", "version": "0.1.0", "dependencies": { + "@material-ui/core": "^4.12.4", + "@material-ui/icons": "^4.11.3", + "@mui/material": "^5.14.19", + "@mui/styles": "^5.15.3", "bootstrap": "^5.3.2", + "date-fns": "^3.2.0", "qs": "^6.11.0", "react": "^18.2.0", "react-bootstrap": "^2.9.0", @@ -1980,9 +1985,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", + "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2317,6 +2322,28 @@ "postcss-selector-parser": "^6.0.10" } }, + "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/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.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", @@ -2330,6 +2357,11 @@ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" }, + "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/stylis": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", @@ -2340,6 +2372,16 @@ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" }, + "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/eslintrc": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.0.tgz", @@ -2411,6 +2453,40 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.3.tgz", + "integrity": "sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==", + "dependencies": { + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.4.tgz", + "integrity": "sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==", + "dependencies": { + "@floating-ui/core": "^1.5.3", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.5.tgz", + "integrity": "sha512-UsBK30Bg+s6+nsgblXtZmwHhgS2vmbuQK22qgt2pTQM6M3X6H1+cQcLXqgRY3ihVLcZJE6IvqDQozhsnIVqK/Q==", + "dependencies": { + "@floating-ui/dom": "^1.5.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -3266,6 +3342,452 @@ "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, + "node_modules/@material-ui/core": { + "version": "4.12.4", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz", + "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", + "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.5", + "@material-ui/system": "^4.12.2", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0", + "react-transition-group": "^4.4.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/core/node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "node_modules/@material-ui/core/node_modules/@material-ui/styles": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", + "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", + "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/core/node_modules/@material-ui/system": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.3", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/core/node_modules/@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@material-ui/core/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/@material-ui/core/node_modules/csstype": { + "version": "2.6.21", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + }, + "node_modules/@material-ui/icons": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.3.tgz", + "integrity": "sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA==", + "dependencies": { + "@babel/runtime": "^7.4.4" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@material-ui/core": "^4.0.0", + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.30.tgz", + "integrity": "sha512-dc38W4W3K42atE9nSaOeoJ7/x9wGIfawdwC/UmMxMLlZ1iSsITQ8dQJaTATCbn98YvYPINK/EH541YA5enQIPQ==", + "dependencies": { + "@babel/runtime": "^7.23.6", + "@floating-ui/react-dom": "^2.0.4", + "@mui/types": "^7.2.12", + "@mui/utils": "^5.15.3", + "@popperjs/core": "^2.11.8", + "clsx": "^2.0.0", + "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", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.3.tgz", + "integrity": "sha512-sWeihiVyxdJjpLkp8SHkTy9kt2M/o11M60G1MzwljGL2BXdM3Ktzqv5QaQHdi00y7Y1ulvtI3GOSxP2xU8mQJw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/material": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.3.tgz", + "integrity": "sha512-DODBBMouyq1B5f3YkEWL9vO8pGCxuEGqtfpltF6peMJzz/78tJFyLQsDas9MNLC/8AdFu2BQdkK7wox5UBPTAA==", + "dependencies": { + "@babel/runtime": "^7.23.6", + "@mui/base": "5.0.0-beta.30", + "@mui/core-downloads-tracker": "^5.15.3", + "@mui/system": "^5.15.3", + "@mui/types": "^7.2.12", + "@mui/utils": "^5.15.3", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.0.0", + "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-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.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.15.3", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.3.tgz", + "integrity": "sha512-Q79MhVMmywC1l5bMsMZq5PsIudr1MNPJnx9/EqdMP0vpz5iNvFpnLmxsD7d8/hqTWgFAljI+LH3jX8MxlZH9Gw==", + "dependencies": { + "@babel/runtime": "^7.23.6", + "@mui/utils": "^5.15.3", + "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.15.3", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.3.tgz", + "integrity": "sha512-+d5XZCTeemOO/vBfWGEeHgTm8fjU1Psdgm+xAw+uegycO2EnoA/EfGSaG5UwZ6g3b66y48Mkxi35AggShMr88w==", + "dependencies": { + "@babel/runtime": "^7.23.6", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.2", + "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/styles": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/styles/-/styles-5.15.3.tgz", + "integrity": "sha512-yePvO+0z35a1Cm7sXy3rL6F1oEJSiDFcQ/4Mkn/MHttwfBbbi7higBbUsBkuLPGoy40EiIUF+Tr+UoNW296/bA==", + "dependencies": { + "@babel/runtime": "^7.23.6", + "@emotion/hash": "^0.9.1", + "@mui/private-theming": "^5.15.3", + "@mui/types": "^7.2.12", + "@mui/utils": "^5.15.3", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.10.0", + "jss-plugin-camel-case": "^10.10.0", + "jss-plugin-default-unit": "^10.10.0", + "jss-plugin-global": "^10.10.0", + "jss-plugin-nested": "^10.10.0", + "jss-plugin-props-sort": "^10.10.0", + "jss-plugin-rule-value-function": "^10.10.0", + "jss-plugin-vendor-prefixer": "^10.10.0", + "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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.3.tgz", + "integrity": "sha512-ewVU4eRgo4VfNMGpO61cKlfWmH7l9s6rA8EknRzuMX3DbSLfmtW2WJJg6qPwragvpPIir0Pp/AdWVSDhyNy5Tw==", + "dependencies": { + "@babel/runtime": "^7.23.6", + "@mui/private-theming": "^5.15.3", + "@mui/styled-engine": "^5.15.3", + "@mui/types": "^7.2.12", + "@mui/utils": "^5.15.3", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "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.12", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.12.tgz", + "integrity": "sha512-3kaHiNm9khCAo0pVe0RenketDSFoZGAlVZ4zDjB/QNZV0XiCj+sh1zkX0VVhQPgYJDlBEzAag+MHJ1tU3vf0Zw==", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.3.tgz", + "integrity": "sha512-mT3LiSt9tZWCdx1pl7q4Q5tNo6gdZbvJel286ZHGuj6LQQXjWNAh8qiF9d+LogvNUI+D7eLkTnj605d1zoazfg==", + "dependencies": { + "@babel/runtime": "^7.23.6", + "@types/prop-types": "^15.7.11", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "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.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, "node_modules/@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -3778,6 +4300,26 @@ "tslib": "^2.4.0" } }, + "node_modules/@testing-library/dom": { + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.3.tgz", + "integrity": "sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/@testing-library/jest-dom": { "version": "5.16.5", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", @@ -4172,9 +4714,9 @@ "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==" }, "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/q": { "version": "1.5.5", @@ -4192,9 +4734,9 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "node_modules/@types/react": { - "version": "18.0.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", - "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "version": "17.0.74", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.74.tgz", + "integrity": "sha512-nBtFGaeTMzpiL/p73xbmCi00SiCQZDTJUk9ZuHOLtil3nI+y7l269LHkHIAYpav99ZwGnPJzuJsJpfLXjiQ52g==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4211,9 +4753,9 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.7.tgz", - "integrity": "sha512-ICCyBl5mvyqYp8Qeq9B5G/fyBSRC0zx3XM3sCC6KkcMsNeAHqXBKkmat4GqdJET5jtYUpZXrxI5flve5qhi2Eg==", + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", "dependencies": { "@types/react": "*" } @@ -6381,6 +6923,15 @@ "node": ">=0.10.0" } }, + "node_modules/css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "dependencies": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "node_modules/css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -6682,15 +7233,12 @@ } }, "node_modules/date-fns": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", - "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", - "engines": { - "node": ">=0.11" - }, + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.2.0.tgz", + "integrity": "sha512-E4KWKavANzeuusPi0jUjpuI22SURAznGkx7eZV+4i6x2A+IZxAMcajgkvuDAU1bg40+xuhW1zRdVIIM/4khuIg==", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" } }, "node_modules/debug": { @@ -9114,6 +9662,11 @@ "node": ">=10.17.0" } }, + "node_modules/hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -9438,6 +9991,11 @@ "node": ">=0.10.0" } }, + "node_modules/is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" + }, "node_modules/is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", @@ -11760,6 +12318,88 @@ "node": ">=0.10.0" } }, + "node_modules/jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", + "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/jss" + } + }, + "node_modules/jss-plugin-camel-case": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", + "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-default-unit": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", + "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-global": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", + "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-nested": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", + "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-props-sort": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", + "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-rule-value-function": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", + "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-vendor-prefixer": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", + "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.10.0" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -12858,6 +13498,11 @@ "node": ">=4" } }, + "node_modules/popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, "node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -14359,6 +15004,21 @@ "react-dom": "^16.9.0 || ^17 || ^18" } }, + "node_modules/react-datepicker/node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -16272,6 +16932,11 @@ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -16459,6 +17124,19 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -18926,9 +19604,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", + "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", "requires": { "regenerator-runtime": "^0.14.0" }, @@ -19108,6 +19786,30 @@ "integrity": "sha512-jwx+WCqszn53YHOfvFMJJRd/B2GqkCBt+1MJSG6o5/s8+ytHMvDZXsJgUEWLk12UnLd7HYKac4BYU5i/Ron1Cw==", "requires": {} }, + "@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "requires": { + "@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" + }, + "dependencies": { + "stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + } + } + }, + "@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==" + }, "@emotion/is-prop-valid": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", @@ -19121,6 +19823,11 @@ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" }, + "@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==" + }, "@emotion/stylis": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", @@ -19131,6 +19838,16 @@ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" }, + "@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==" + }, + "@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==" + }, "@eslint/eslintrc": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.0.tgz", @@ -19180,6 +19897,36 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.35.0.tgz", "integrity": "sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==" }, + "@floating-ui/core": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.3.tgz", + "integrity": "sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==", + "requires": { + "@floating-ui/utils": "^0.2.0" + } + }, + "@floating-ui/dom": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.4.tgz", + "integrity": "sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==", + "requires": { + "@floating-ui/core": "^1.5.3", + "@floating-ui/utils": "^0.2.0" + } + }, + "@floating-ui/react-dom": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.5.tgz", + "integrity": "sha512-UsBK30Bg+s6+nsgblXtZmwHhgS2vmbuQK22qgt2pTQM6M3X6H1+cQcLXqgRY3ihVLcZJE6IvqDQozhsnIVqK/Q==", + "requires": { + "@floating-ui/dom": "^1.5.4" + } + }, + "@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, "@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -19881,6 +20628,229 @@ "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, + "@material-ui/core": { + "version": "4.12.4", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz", + "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.5", + "@material-ui/system": "^4.12.2", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0", + "react-transition-group": "^4.4.0" + }, + "dependencies": { + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "@material-ui/styles": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", + "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + } + }, + "@material-ui/system": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.3", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + } + }, + "@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + } + }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + }, + "csstype": { + "version": "2.6.21", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + } + } + }, + "@material-ui/icons": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.3.tgz", + "integrity": "sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA==", + "requires": { + "@babel/runtime": "^7.4.4" + } + }, + "@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", + "requires": {} + }, + "@mui/base": { + "version": "5.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.30.tgz", + "integrity": "sha512-dc38W4W3K42atE9nSaOeoJ7/x9wGIfawdwC/UmMxMLlZ1iSsITQ8dQJaTATCbn98YvYPINK/EH541YA5enQIPQ==", + "requires": { + "@babel/runtime": "^7.23.6", + "@floating-ui/react-dom": "^2.0.4", + "@mui/types": "^7.2.12", + "@mui/utils": "^5.15.3", + "@popperjs/core": "^2.11.8", + "clsx": "^2.0.0", + "prop-types": "^15.8.1" + } + }, + "@mui/core-downloads-tracker": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.3.tgz", + "integrity": "sha512-sWeihiVyxdJjpLkp8SHkTy9kt2M/o11M60G1MzwljGL2BXdM3Ktzqv5QaQHdi00y7Y1ulvtI3GOSxP2xU8mQJw==" + }, + "@mui/material": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.3.tgz", + "integrity": "sha512-DODBBMouyq1B5f3YkEWL9vO8pGCxuEGqtfpltF6peMJzz/78tJFyLQsDas9MNLC/8AdFu2BQdkK7wox5UBPTAA==", + "requires": { + "@babel/runtime": "^7.23.6", + "@mui/base": "5.0.0-beta.30", + "@mui/core-downloads-tracker": "^5.15.3", + "@mui/system": "^5.15.3", + "@mui/types": "^7.2.12", + "@mui/utils": "^5.15.3", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, + "@mui/private-theming": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.3.tgz", + "integrity": "sha512-Q79MhVMmywC1l5bMsMZq5PsIudr1MNPJnx9/EqdMP0vpz5iNvFpnLmxsD7d8/hqTWgFAljI+LH3jX8MxlZH9Gw==", + "requires": { + "@babel/runtime": "^7.23.6", + "@mui/utils": "^5.15.3", + "prop-types": "^15.8.1" + } + }, + "@mui/styled-engine": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.3.tgz", + "integrity": "sha512-+d5XZCTeemOO/vBfWGEeHgTm8fjU1Psdgm+xAw+uegycO2EnoA/EfGSaG5UwZ6g3b66y48Mkxi35AggShMr88w==", + "requires": { + "@babel/runtime": "^7.23.6", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + } + }, + "@mui/styles": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/styles/-/styles-5.15.3.tgz", + "integrity": "sha512-yePvO+0z35a1Cm7sXy3rL6F1oEJSiDFcQ/4Mkn/MHttwfBbbi7higBbUsBkuLPGoy40EiIUF+Tr+UoNW296/bA==", + "requires": { + "@babel/runtime": "^7.23.6", + "@emotion/hash": "^0.9.1", + "@mui/private-theming": "^5.15.3", + "@mui/types": "^7.2.12", + "@mui/utils": "^5.15.3", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.10.0", + "jss-plugin-camel-case": "^10.10.0", + "jss-plugin-default-unit": "^10.10.0", + "jss-plugin-global": "^10.10.0", + "jss-plugin-nested": "^10.10.0", + "jss-plugin-props-sort": "^10.10.0", + "jss-plugin-rule-value-function": "^10.10.0", + "jss-plugin-vendor-prefixer": "^10.10.0", + "prop-types": "^15.8.1" + } + }, + "@mui/system": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.3.tgz", + "integrity": "sha512-ewVU4eRgo4VfNMGpO61cKlfWmH7l9s6rA8EknRzuMX3DbSLfmtW2WJJg6qPwragvpPIir0Pp/AdWVSDhyNy5Tw==", + "requires": { + "@babel/runtime": "^7.23.6", + "@mui/private-theming": "^5.15.3", + "@mui/styled-engine": "^5.15.3", + "@mui/types": "^7.2.12", + "@mui/utils": "^5.15.3", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + } + }, + "@mui/types": { + "version": "7.2.12", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.12.tgz", + "integrity": "sha512-3kaHiNm9khCAo0pVe0RenketDSFoZGAlVZ4zDjB/QNZV0XiCj+sh1zkX0VVhQPgYJDlBEzAag+MHJ1tU3vf0Zw==", + "requires": {} + }, + "@mui/utils": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.3.tgz", + "integrity": "sha512-mT3LiSt9tZWCdx1pl7q4Q5tNo6gdZbvJel286ZHGuj6LQQXjWNAh8qiF9d+LogvNUI+D7eLkTnj605d1zoazfg==", + "requires": { + "@babel/runtime": "^7.23.6", + "@types/prop-types": "^15.7.11", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, "@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -20203,6 +21173,23 @@ "tslib": "^2.4.0" } }, + "@testing-library/dom": { + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.3.tgz", + "integrity": "sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==", + "dev": true, + "peer": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + } + }, "@testing-library/jest-dom": { "version": "5.16.5", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", @@ -20563,9 +21550,9 @@ "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==" }, "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "@types/q": { "version": "1.5.5", @@ -20583,9 +21570,9 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "@types/react": { - "version": "18.0.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", - "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "version": "17.0.74", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.74.tgz", + "integrity": "sha512-nBtFGaeTMzpiL/p73xbmCi00SiCQZDTJUk9ZuHOLtil3nI+y7l269LHkHIAYpav99ZwGnPJzuJsJpfLXjiQ52g==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -20602,9 +21589,9 @@ } }, "@types/react-transition-group": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.7.tgz", - "integrity": "sha512-ICCyBl5mvyqYp8Qeq9B5G/fyBSRC0zx3XM3sCC6KkcMsNeAHqXBKkmat4GqdJET5jtYUpZXrxI5flve5qhi2Eg==", + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", "requires": { "@types/react": "*" } @@ -22195,6 +23182,15 @@ } } }, + "css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "requires": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -22415,9 +23411,9 @@ } }, "date-fns": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", - "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.2.0.tgz", + "integrity": "sha512-E4KWKavANzeuusPi0jUjpuI22SURAznGkx7eZV+4i6x2A+IZxAMcajgkvuDAU1bg40+xuhW1zRdVIIM/4khuIg==" }, "debug": { "version": "4.3.4", @@ -24206,6 +25202,11 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" }, + "hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -24424,6 +25425,11 @@ "is-extglob": "^2.1.1" } }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" + }, "is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", @@ -26255,6 +27261,84 @@ "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==" }, + "jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", + "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", + "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.10.0" + } + }, + "jss-plugin-default-unit": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", + "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "jss-plugin-global": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", + "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "jss-plugin-nested": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", + "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", + "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", + "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", + "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.10.0" + } + }, "jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -27046,6 +28130,11 @@ } } }, + "popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, "postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -27943,6 +29032,16 @@ "prop-types": "^15.7.2", "react-onclickoutside": "^6.12.2", "react-popper": "^2.3.0" + }, + "dependencies": { + "date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "requires": { + "@babel/runtime": "^7.21.0" + } + } } }, "react-dev-utils": { @@ -29359,6 +30458,11 @@ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -29504,6 +30608,12 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "peer": true + }, "unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", diff --git a/egovframe-template-simple-react-contribution/package.json b/egovframe-template-simple-react-contribution/package.json index ed30ed4..23ee0c8 100644 --- a/egovframe-template-simple-react-contribution/package.json +++ b/egovframe-template-simple-react-contribution/package.json @@ -19,7 +19,8 @@ "react-scripts": "5.0.1", "recharts": "^2.10.3", "styled-components": "^6.0.9", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "date-fns": "^3.2.0" }, "devDependencies": { "@testing-library/jest-dom": "^5.16.4", diff --git a/egovframe-template-simple-react-contribution/src/api/egovFetch.js b/egovframe-template-simple-react-contribution/src/api/egovFetch.js index 4d3e989..f634fb1 100644 --- a/egovframe-template-simple-react-contribution/src/api/egovFetch.js +++ b/egovframe-template-simple-react-contribution/src/api/egovFetch.js @@ -10,6 +10,16 @@ export function getQueryString(params){ return `?${Object.entries(params).map(e => e.join('=')).join('&') }` } +export function convParams(params){ + let str = "?" + for(let key in params){ + if(params[key]){ + str = str+key+"="+params[key]+"&"; + } + } + return str; +} + export function requestFetch(url, requestOptions, handler, errorHandler) { console.groupCollapsed("requestFetch"); console.log("requestFetch [URL] : ", SERVER_URL + url); diff --git a/egovframe-template-simple-react-contribution/src/components/commonCode/CheckBox.jsx b/egovframe-template-simple-react-contribution/src/components/commonCode/CheckBox.jsx new file mode 100644 index 0000000..1d00e02 --- /dev/null +++ b/egovframe-template-simple-react-contribution/src/components/commonCode/CheckBox.jsx @@ -0,0 +1,56 @@ +import React, {useCallback, useEffect, useState} from "react"; +import Form from "react-bootstrap/Form"; +import * as EgovNet from "api/egovFetch"; + +function CheckBox({name, grpCd, selectedValue}){ + + const [checkBox, setCheckBox] = useState(); + + useEffect(() => { + getCodeItemList() + }, []); + + useEffect(() => { + if(selectedValue){ + const itemCdAry = selectedValue.split(','); + itemCdAry.forEach(function(itemCd){ + document.querySelector(`#chkBox_${itemCd}`).checked = true; + }) + } + }, [selectedValue]); + + function getCodeItemList() { + EgovNet.requestFetch( + '/commonCode/code-item?grpCd='+grpCd, + { + method: "GET" + }, + (resp) => { + let checkBoxTag = []; + resp.result.codeList.forEach(function (item, index) { + checkBoxTag.push( + + ); + }); + setCheckBox(checkBoxTag); + }, + function (resp) { + console.log("err response : ", resp); + } + ); + } + + return ( +
+ {checkBox} +
+ ) +} + +export default CheckBox; \ No newline at end of file diff --git a/egovframe-template-simple-react-contribution/src/components/commonCode/SelectOption.jsx b/egovframe-template-simple-react-contribution/src/components/commonCode/SelectOption.jsx new file mode 100644 index 0000000..eb37263 --- /dev/null +++ b/egovframe-template-simple-react-contribution/src/components/commonCode/SelectOption.jsx @@ -0,0 +1,46 @@ +import React, {useEffect, useState} from "react"; +import Form from "react-bootstrap/Form"; +import * as EgovNet from "api/egovFetch"; + +function SelectOption({name, grpCd, selectedValue}){ + + const [options, setOptions] = useState(); + const [value, setValue] = useState(selectedValue) + + useEffect(() => { + getCodeItemList() + }, []); + useEffect(() => { + setValue(selectedValue) + }, [selectedValue]); + + function getCodeItemList(){ + EgovNet.requestFetch( + '/commonCode/code-item?grpCd='+grpCd, + { + method: "GET" + }, + (resp) => { + let optionTag = []; + // 리스트 항목 구성 + resp.result.codeList.forEach(function (item, index) { + optionTag.push( + + ); + }); + setOptions(optionTag); + }, + function (resp) { + console.log("err response : ", resp); + } + ); + } + + return ( + {setValue(e.target.value)}}> + {options} + + ) +} + +export default SelectOption; \ No newline at end of file diff --git a/egovframe-template-simple-react-contribution/src/components/leftmenu/EgovLeftNavAdmin.jsx b/egovframe-template-simple-react-contribution/src/components/leftmenu/EgovLeftNavAdmin.jsx index 3c04028..8b3e83a 100644 --- a/egovframe-template-simple-react-contribution/src/components/leftmenu/EgovLeftNavAdmin.jsx +++ b/egovframe-template-simple-react-contribution/src/components/leftmenu/EgovLeftNavAdmin.jsx @@ -40,6 +40,19 @@ function EgovLeftNavAdmin(props) {

사이트관리

+ + 사이트 관리 + +
    +
  • (isActive ? "cur" : "")}>Dashboard
  • + {/*
  • (isActive ? "cur" : "")}>게시판생성관리
  • +
  • (isActive ? "cur" : "")}>게시판사용관리
  • +
  • (isActive ? "cur" : "")}>공지사항관리
  • +
  • (isActive ? "cur" : "")}>사이트갤러리관리
  • +
  • (isActive ? "cur" : "")}>사이트관리자 암호변경
  • */} +
+
+
환경설정 @@ -93,7 +106,7 @@ function EgovLeftNavAdmin(props) {
  • (isActive ? "cur" : "")}>설문 관리
  • (isActive ? "cur" : "")}>팝업 관리
  • (isActive ? "cur" : "")}>건설기준연구 관리
  • -
  • (isActive ? "cur" : "")}>문자 발송
  • + {/*
  • (isActive ? "cur" : "")}>문자 발송
  • */}
    @@ -119,19 +132,6 @@ function EgovLeftNavAdmin(props) { - - 전자정부 기본 메뉴 - -
      -
    • (isActive ? "cur" : "")}>일정관리
    • -
    • (isActive ? "cur" : "")}>게시판생성관리
    • -
    • (isActive ? "cur" : "")}>게시판사용관리
    • -
    • (isActive ? "cur" : "")}>공지사항관리
    • -
    • (isActive ? "cur" : "")}>사이트갤러리관리
    • -
    • (isActive ? "cur" : "")}>사이트관리자 암호변경
    • -
    -
    -
    diff --git a/egovframe-template-simple-react-contribution/src/css/component.css b/egovframe-template-simple-react-contribution/src/css/component.css index 46b1639..150f740 100644 --- a/egovframe-template-simple-react-contribution/src/css/component.css +++ b/egovframe-template-simple-react-contribution/src/css/component.css @@ -251,6 +251,7 @@ select::-ms-expand {display:none;} .active {background-color: #007bff; color: #fff;} .f_input {height: 46px; padding: 0 20px; border: 0; border-radius: 5px; color: #222; font-size: 16px; background: #f7f7f7;} +.f_input1 {width:200px; height: 32px; padding: 0 30px 0 0; border: 0; border-radius: 5px; color: #222; font-size: 16px; background: #f7f7f7 url(css/images/bg_btn_calendar.png) no-repeat;background-position: right center; background-size: 32px 32px; cursor: pointer;} /* made by lim f_input1*/ .f_input2 {height: 46px; padding: 0 20px; border: 1px solid #dde2e5; border-radius: 5px !important; color: #222; font-size: 16px; background: #fff;} .f_txtar {padding: 10px 19px; border: 1px solid #dde2e5; border-radius: 5px; color: #222; font-size: 16px; line-height: 24px; resize: none;} @@ -301,4 +302,30 @@ select::-ms-expand {display:none;} .react-datepicker__input-container {display: inline-block; vertical-align: top; width: auto;} /* 리액트 관련 */ -.react-datepicker__tab-loop {display: inline-block;} \ No newline at end of file +.react-datepicker__tab-loop {display: inline-block;} + +/* recharts */ +.recharts-tooltip-wrapper .custom-tooltip { + background-color: hsla(0,0%,100%,.8); + border: 1px solid #f5f5f5; + line-height: 24px; + margin: 0; + padding: 10px; + width: 200px +} + +.recharts-tooltip-wrapper .custom-tooltip .label { + color: #666; + margin: 0 +} + +.recharts-tooltip-wrapper .custom-tooltip .desc { + color: #999; + margin: 0 +} + +.recharts-tooltip-wrapper .custom-tooltip .intro { + border-top: 1px solid #f5f5f5; + font-weight: 700; + margin: 0 +} \ No newline at end of file diff --git a/egovframe-template-simple-react-contribution/src/css/page.css b/egovframe-template-simple-react-contribution/src/css/page.css index dd51e33..791049e 100644 --- a/egovframe-template-simple-react-contribution/src/css/page.css +++ b/egovframe-template-simple-react-contribution/src/css/page.css @@ -14,6 +14,7 @@ .Plogin .login_box button span {display: block; position: relative; height: 100%;} .Plogin .login_box .chk {margin-top: 20px;} .Plogin .login_box .chk em {display: inline-block; height: 30px; margin-left: 40px; color: #666; font-size: 16px;} +.Plogin .login_box .chk label {display: inline-block; height: 30px; color: #666; font-size: 16px;} .Plogin .list {margin-top: 44px; padding: 0 360px;} .Plogin .list li {position: relative; padding-left: 15px; color: #666; font-size: 16px; line-height: 26px;} .Plogin .list li::before {content: ""; display: block; position: absolute; left: 0; top: 12px; width: 4px; height: 4px; background: #666;} @@ -168,6 +169,28 @@ .userList .result .list_item > div:nth-child(6) {width: 100px;} .userList .result .list_item > div:nth-child(7) {width: 100px;} + /* 사이트관리 > 환경설정 > 메뉴관리 */ + .menuList .head > span:nth-child(1) {width: 60px;} + .menuList .head > span:nth-child(2) {width: 100px;} + .menuList .head > span:nth-child(3) {width: 100px;} + .menuList .head > span:nth-child(4) {width: 120px;} + .menuList .head > span:nth-child(5) {width: 100px;} + .menuList .head > span:nth-child(6) {width: 100px;} + .menuList .head > span:nth-child(7) {width: 100px;} + .menuList .head > span:nth-child(8) {width: 100px;} + .menuList .head > span:nth-child(9) {width: 100px;} + .menuList .head > span:nth-child(10) {width: 100px;} + .menuList .result .list_item > div:nth-child(1) {width: 60px;} + .menuList .result .list_item > div:nth-child(2) {width: 100px;} + .menuList .result .list_item > div:nth-child(3) {width: 100px;} + .menuList .result .list_item > div:nth-child(4) {width: 120px;} + .menuList .result .list_item > div:nth-child(5) {width: 100px;} + .menuList .result .list_item > div:nth-child(6) {width: 100px;} + .menuList .result .list_item > div:nth-child(7) {width: 100px;} + .menuList .result .list_item > div:nth-child(8) {width: 100px;} + .menuList .result .list_item > div:nth-child(9) {width: 100px;} + .menuList .result .list_item > div:nth-child(10) {width: 100px;} + /* 사이트소개 */ .SITE_INTRO .ds_1 .t_1 {margin-top: 52px; color: #000; font-size: 26px; font-weight: 500; text-align: center;} .SITE_INTRO .ds_1 .li_1 {position: relative; margin-top: 34px; font-size: 0; text-align: center;} @@ -250,6 +273,12 @@ .BRD009 .result .list_item > div:nth-child(5) {width: 150px;} .BRD009 .result .list_item > div:nth-child(6) {width: 150px;} + /* 로그현황 - 메뉴별/사용자별 접속현황*/ + .BRD010 .head > span:nth-child(1) {width: 60%;} + .BRD010 .head > span:nth-child(2) {width: 40%;} + .BRD010 .result .list_item > div:nth-child(1) {width: 60%; text-overflow: ellipsis; white-space: nowrap; overflow: hidden;} + .BRD010 .result .list_item > div:nth-child(2) {width: 40%;} + /* 게시판 사용관리 등록 */ .BOARD_USE_LIST .board_view2 dl dt {width: 185px;} .BOARD_USE_LIST .board_view2 dl:nth-child(2) dd .f_input2 {width: 490px; margin-left: 17px;} diff --git a/egovframe-template-simple-react-contribution/src/css/response.css b/egovframe-template-simple-react-contribution/src/css/response.css index 782e0ed..a133244 100644 --- a/egovframe-template-simple-react-contribution/src/css/response.css +++ b/egovframe-template-simple-react-contribution/src/css/response.css @@ -447,6 +447,13 @@ .BRD009 .result .list_item > div:nth-child(6)::after {content: ""; display: inline-block; width: 1px; height: 11px; margin-left: 6px; background: #ccc; vertical-align: 0px;} .BRD009 .result .list_item > div:nth-child(6)::after {content: none;} + /* 로그현황 - 메뉴별/사용자별 접속현황*/ + .BRD010 .head {border-top: 1px solid #dde2e5;} + .BRD010 .result .list_item {padding: 16px 0; border-bottom: 1px solid #dde2e5;} + .BRD010 .result .list_item > div {border-bottom: 0; font-size: 14px;} + .BRD010 .result .list_item > div:nth-child(1) {width: 60%;} + .BRD010 .result .list_item > div:nth-child(2) {width: 40%; padding: 0 0 2px 0; font-weight: 700; text-align: left;} + .BOARD_USE_LIST .board_view2 dl dt {width: 95px;} .BOARD_USE_LIST .board_view2 dl:nth-child(2) dd .f_select {width: 100%;} .BOARD_USE_LIST .board_view2 dl:nth-child(2) dd .f_input2 {width: 100%; margin: 15px 0 0 0;} @@ -553,5 +560,7 @@ .BRD009 .result .list_item > div:nth-child(4)::after, .BRD009 .result .list_item > div:nth-child(5)::after, .BRD009 .result .list_item > div:nth-child(6)::after {margin-left: 15px;} - + + /* 로그현황 - 메뉴별/사용자별 접속현황*/ + /*.BRD010 .result .list_item > div:nth-child(1)*/ } \ No newline at end of file diff --git a/egovframe-template-simple-react-contribution/src/pages/admin/config/MenuMgt.jsx b/egovframe-template-simple-react-contribution/src/pages/admin/config/MenuMgt.jsx index cc191b1..450794f 100644 --- a/egovframe-template-simple-react-contribution/src/pages/admin/config/MenuMgt.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/admin/config/MenuMgt.jsx @@ -1,11 +1,54 @@ -import React from 'react'; +import React, {useCallback, useEffect, useState} from 'react'; +import {Link} from "react-router-dom"; +import URL from "constants/url"; + +import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin'; -function MenuMgt(props) { +function MenuMgt({}) { return (
    - MenuMgt +
    +
    +
      +
    • Home
    • +
    • 사이트관리
    • +
    • 환경설정
    • +
    • 메뉴 관리
    • +
    +
    +
    + {/* */} + +
    + {/* */} + +
    +

    메뉴 관리

    +
    +

    + +
    +
    + 아이디 + 이름 + 그룹 + 레벨 + 정렬 + URI + 타입 + CSS + IMG + 삭제 +
    +
    + {/*{listTag}*/} +
    +
    +
    +
    +
    ); } diff --git a/egovframe-template-simple-react-contribution/src/pages/admin/logs/MenuAccessInfo.jsx b/egovframe-template-simple-react-contribution/src/pages/admin/logs/MenuAccessInfo.jsx index 455de22..0815629 100644 --- a/egovframe-template-simple-react-contribution/src/pages/admin/logs/MenuAccessInfo.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/admin/logs/MenuAccessInfo.jsx @@ -1,13 +1,230 @@ -import React from 'react'; +import React, {useState, useEffect, useCallback, useRef, PureComponent} from 'react'; +import { Link, useLocation } from 'react-router-dom'; +import {BarChart, Bar, Rectangle, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer} from 'recharts'; + +import DatePicker from 'react-datepicker'; +import 'react-datepicker/dist/react-datepicker.css'; + +import {format, sub} from "date-fns"; +import { ko } from 'date-fns/locale'; + +import * as EgovNet from 'api/egovFetch'; +import URL from 'constants/url'; + +import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin'; + +import { itemIdxByPage } from 'utils/calc'; -function MenuAccessInfo(props) { +function MenuConnections(props) { + // console.group("EgovAdminPrivacyList"); + // console.log("[Start] EgovAdminPrivacyList ------------------------------"); + // console.log("EgovAdminPrivacyList [props] : ", props); + const nowDate = new Date(); + const oneMonthAgoDate = sub(nowDate, { months: 1 }); + const [start_date, setStartDate] = useState(oneMonthAgoDate); + const [end_date, setEndDate] = useState(nowDate); // new Date() + + const location = useLocation(); + // console.log("EgovAdminPrivacyList [location] : ", location); + + // eslint-disable-next-line no-unused-vars + const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || {start_date: format(start_date, "yyyy-MM-dd"), end_date: format(end_date, "yyyy-MM-dd")}); + const [chartData, setChartData] = useState([]); + + const [listTag, setListTag] = useState([]); + + const retrieveList = useCallback((srchCnd) => { + // console.groupCollapsed("EgovAdminUsageList.retrieveList()"); + const retrieveListURL = '/admin/logs/menu'; + + const requestOptions = { + method: "POST", + headers: { + 'Content-type': 'application/json', + }, + body: JSON.stringify(srchCnd) + } + + EgovNet.requestFetch( + retrieveListURL, + requestOptions, + (resp) => { + let mutListTag = []; + + const resultCnt = parseInt(resp.result.resultCnt); + const currentPageNo = 1; // resp.result.paginationInfo.currentPageNo; + const pageSize = resultCnt; // resp.result.paginationInfo.pageSize; + + // 리스트 항목 구성 + if (resultCnt === 0) { + mutListTag.push(

    데이터가 없습니다.

    ); + } else { + resp.result.resultList.forEach(function (item, index) { + // if (index === 0) mutListTag = []; // 목록 초기화 + const listIdx = itemIdxByPage(resultCnt, currentPageNo, pageSize, index); + + mutListTag.push( +
    +
    {item[1]}
    +
    {item[2].toLocaleString()}
    +
    + ); + }); + } + setListTag(mutListTag); + + let chartDataArray = resp.result.resultList.map((item, index) => ({ + logCnt: item[1], // Assuming logCnt is the x-axis data + "접속수": item[2], // Assuming menuTitle is the y-axis data + })); + setChartData(chartDataArray); + }, + function (resp) { + console.log("err response : ", resp); + } + ); + // console.groupEnd("EgovAdminPrivacyList.retrieveList()"); + },[listTag]); + + const CustomTooltip = ({ active, payload, label }) => { + if (active && payload && payload.length) { + return ( +
    +

    메뉴별 접속현황

    +

    {`${label} : ${payload[0].value}`}

    + {/*

    Anything you want can be displayed here.

    */} +
    + ); + } + return null; + }; + + useEffect(() => { + retrieveList(searchCondition); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [start_date, end_date]); + + // console.log("------------------------------EgovAdminPrivacyList [End]"); + // console.groupEnd("EgovAdminPrivacyList"); return (
    - MenuAccessInfo +
    + {/* */} +
    +
      +
    • Home
    • +
    • 사이트관리
    • +
    • 로그현황
    • +
    • 메뉴별 접속현황
    • +
    +
    + {/* */} + +
    + {/* */} + + {/* */} + +
    + {/* */} + +
    +

    메뉴별 접속현황

    +
    + + {/* */} +
    +
      +
    • + { + setStartDate(date); + setSearchCondition({ + start_date: format(date, "yyyy-MM-dd"), + end_date: format(end_date, "yyyy-MM-dd") + }); + }} + /> - +
    • +
    • + { + setEndDate(date); + setSearchCondition({ + start_date: format(start_date, "yyyy-MM-dd"), + end_date: format(date, "yyyy-MM-dd") + }); + }} + /> +
    • +
    +
    + {/* */} + + {/* */} +
    +
    +
    +
    + 메뉴명 + 접속횟수 +
    +
    + {listTag} +
    +
    +
    +
    + + + + + + } /> + + } /> + + +
    +
    + {/* */} + + {/* */} +
    +
    +
    ); } -export default MenuAccessInfo; \ No newline at end of file +export default MenuConnections; \ No newline at end of file diff --git a/egovframe-template-simple-react-contribution/src/pages/admin/logs/PrivacyLogs.jsx b/egovframe-template-simple-react-contribution/src/pages/admin/logs/PrivacyLogs.jsx index 7fadf32..86d95d6 100644 --- a/egovframe-template-simple-react-contribution/src/pages/admin/logs/PrivacyLogs.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/admin/logs/PrivacyLogs.jsx @@ -96,6 +96,7 @@ function PrivacyConnections(props) {
  • Home
  • 사이트관리
  • 로그현황
  • +
  • 개인정보 로그현황
  • {/* */} @@ -112,7 +113,7 @@ function PrivacyConnections(props) {

    개인정보 로그현황

    - {/* */} + {/* */}
    번호 @@ -126,7 +127,7 @@ function PrivacyConnections(props) { {listTag}
    - {/* */} + {/* */}
    {/* */} diff --git a/egovframe-template-simple-react-contribution/src/pages/admin/logs/UserConnections.jsx b/egovframe-template-simple-react-contribution/src/pages/admin/logs/UserConnections.jsx index cad6625..44ac15f 100644 --- a/egovframe-template-simple-react-contribution/src/pages/admin/logs/UserConnections.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/admin/logs/UserConnections.jsx @@ -1,11 +1,228 @@ -import React from 'react'; +import React, {useState, useEffect, useCallback, useRef, PureComponent} from 'react'; +import { Link, useLocation } from 'react-router-dom'; +import {BarChart, Bar, Rectangle, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer} from 'recharts'; +import DatePicker from 'react-datepicker'; +import 'react-datepicker/dist/react-datepicker.css'; + +import {format, sub} from "date-fns"; +import { ko } from 'date-fns/locale'; + +import * as EgovNet from 'api/egovFetch'; +import URL from 'constants/url'; + +import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin'; + +import { itemIdxByPage } from 'utils/calc'; function UserConnections(props) { + // console.group("EgovAdminPrivacyList"); + // console.log("[Start] EgovAdminPrivacyList ------------------------------"); + // console.log("EgovAdminPrivacyList [props] : ", props); + const nowDate = new Date(); + const oneMonthAgoDate = sub(nowDate, { months: 1 }); + const [start_date, setStartDate] = useState(oneMonthAgoDate); + const [end_date, setEndDate] = useState(nowDate); // new Date() + + const location = useLocation(); + // console.log("EgovAdminPrivacyList [location] : ", location); + + // eslint-disable-next-line no-unused-vars + const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || {start_date: format(start_date, "yyyy-MM-dd"), end_date: format(end_date, "yyyy-MM-dd")}); + const [chartData, setChartData] = useState([]); + + const [listTag, setListTag] = useState([]); + + const retrieveList = useCallback((srchCnd) => { + // console.groupCollapsed("EgovAdminUsageList.retrieveList()"); + const retrieveListURL = '/admin/logs/user'; + + const requestOptions = { + method: "POST", + headers: { + 'Content-type': 'application/json', + }, + body: JSON.stringify(srchCnd) + } + + EgovNet.requestFetch( + retrieveListURL, + requestOptions, + (resp) => { + let mutListTag = []; + + const resultCnt = parseInt(resp.result.resultCnt); + const currentPageNo = 1; // resp.result.paginationInfo.currentPageNo; + const pageSize = resultCnt; // resp.result.paginationInfo.pageSize; + + // 리스트 항목 구성 + if (resultCnt === 0) { + mutListTag.push(

    데이터가 없습니다.

    ); + } else { + resp.result.resultList.forEach(function (item, index) { + // if (index === 0) mutListTag = []; // 목록 초기화 + const listIdx = itemIdxByPage(resultCnt, currentPageNo, pageSize, index); + + mutListTag.push( +
    +
    {item[0]}
    +
    {item[1].toLocaleString()}
    +
    + ); + }); + } + setListTag(mutListTag); + + let chartDataArray = resp.result.resultList.map((item, index) => ({ + logCnt: item[0], // Assuming logCnt is the x-axis data + "접속수": item[1], // Assuming menuTitle is the y-axis data + })); + setChartData(chartDataArray); + }, + function (resp) { + console.log("err response : ", resp); + } + ); + // console.groupEnd("EgovAdminPrivacyList.retrieveList()"); + },[listTag]); + + const CustomTooltip = ({ active, payload, label }) => { + if (active && payload && payload.length) { + return ( +
    +

    사용자 접속현황

    +

    {`${label} : ${payload[0].value}`}

    + {/*

    Anything you want can be displayed here.

    */} +
    + ); + } + return null; + }; + + useEffect(() => { + retrieveList(searchCondition); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [start_date, end_date]); + + // console.log("------------------------------EgovAdminPrivacyList [End]"); + // console.groupEnd("EgovAdminPrivacyList"); + return (
    - UserConnections +
    + {/* */} +
    +
      +
    • Home
    • +
    • 사이트관리
    • +
    • 로그현황
    • +
    • 사용자 접속현황
    • +
    +
    + {/* */} + +
    + {/* */} + + {/* */} + +
    + {/* */} + +
    +

    사용자 접속현황

    +
    + + {/* */} +
    +
      +
    • + { + setStartDate(date); + setSearchCondition({ + start_date: format(date, "yyyy-MM-dd"), + end_date: format(end_date, "yyyy-MM-dd") + }); + }} + /> - +
    • +
    • + { + setEndDate(date); + setSearchCondition({ + start_date: format(start_date, "yyyy-MM-dd"), + end_date: format(date, "yyyy-MM-dd") + }); + }} + /> +
    • +
    +
    + {/* */} + + {/* */} +
    +
    +
    +
    + 접속일자 + 접속횟수 +
    +
    + {listTag} +
    +
    +
    +
    + + + + + + } /> + + } /> + + +
    +
    + {/* */} + + {/* */} +
    +
    +
    ); } diff --git a/egovframe-template-simple-react-contribution/src/pages/admin/schedule/EgovAdminScheduleList.jsx b/egovframe-template-simple-react-contribution/src/pages/admin/schedule/EgovAdminScheduleList.jsx index 8971e61..42ec74b 100644 --- a/egovframe-template-simple-react-contribution/src/pages/admin/schedule/EgovAdminScheduleList.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/admin/schedule/EgovAdminScheduleList.jsx @@ -337,82 +337,13 @@ function EgovAdminScheduleList(props) {

    사이트관리

    -

    일정관리

    +

    - - {/* */} -
    -
      -
    • - -
    • -
    • - - {searchCondition.year} - -
    • -
    • - - {(searchCondition.month + 1)} - -
    • -
    -
    - {/* */} - -
    - - - - - - - - - - - - - - {calendarTag} - -
    -
    - {/* */} diff --git a/egovframe-template-simple-react-contribution/src/pages/admin/users/List.jsx b/egovframe-template-simple-react-contribution/src/pages/admin/users/List.jsx index 8e63171..bb23dc2 100644 --- a/egovframe-template-simple-react-contribution/src/pages/admin/users/List.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/admin/users/List.jsx @@ -1,26 +1,27 @@ -import React, {useCallback, useEffect, useRef, useState} from 'react'; -import {Link, useLocation} from "react-router-dom"; +import React, {useCallback, useEffect, useState} from 'react'; +import {Link} from "react-router-dom"; import URL from "constants/url"; import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin'; import EgovPaging from "components/EgovPaging"; import * as EgovNet from "api/egovFetch"; -import {itemIdxByPage} from "utils/calc"; import Modal from "react-bootstrap/Modal"; import UserInfoModal from "./UserInfoModal"; +import CODE from "../../../constants/code"; -function List(props) { +function List({}) { - const location = useLocation(); + const [searchCondition, setSearchCondition] = useState({ + pageIndex: 1, + userSe: '', + searchCondition: 'id', + searchKeyword: '' + }); - const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || { pageIndex: 1, searchCnd: '0', searchWrd: '' });// 기존 조회에서 접근 했을 시 || 신규로 접근 했을 시 const [listTag, setListTag] = useState([]); const [paginationInfo, setPaginationInfo] = useState({}); - const cndRef = useRef(); - const wrdRef = useRef(); - const [show, setShow] = useState(false); const [modalBody, setModalBody] = useState(); @@ -28,7 +29,7 @@ function List(props) { const handleShow = () => setShow(true); const retrieveList = useCallback((searchCondition) => { - const params = "?"; + const params = EgovNet.convParams(searchCondition); EgovNet.requestFetch( '/admin/users/list'+params, { @@ -36,28 +37,20 @@ function List(props) { }, (resp) => { setPaginationInfo(resp.result.paginationInfo); - let mutListTag = []; - const resultCnt = parseInt(resp.result.contentCnt); - const currentPageNo = resp.result.paginationInfo.pageIndex; - const pageSize = resp.result.paginationInfo.rowCnt; - setListTag([]); // 리스트 항목 구성 resp.result.userList.forEach(function (item, index) { - - const listIdx = itemIdxByPage(resultCnt , currentPageNo, pageSize, index); - mutListTag.push( -
    +
    {item.userSe}
    {userInfoModal(item.userSeq)}}>{item.userId}
    {item.userNm}
    {item.email}
    {item.phoneNum}
    {item.status}
    -
    +
    ); }); @@ -74,10 +67,41 @@ function List(props) { retrieveList(searchCondition); }, []); + useEffect(() => { + retrieveList(searchCondition); + }, [searchCondition.pageIndex]); + + const movePage = useCallback((passedPage) => { + setSearchCondition({...searchCondition, pageIndex: passedPage}) + }); + function userInfoModal(userSeq){ handleShow() - setModalBody() + setModalBody() } + + const removeUserInfo = useCallback((seq)=>{ + if(window.confirm("삭제하시겠습니까?\n복구할 수 없습니다.")){ + EgovNet.requestFetch( + '/admin/users/info', + { + method: "DELETE", + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify({userSeq: seq}) + }, + (resp) => { + if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { + alert("삭제되었습니다.") + retrieveList(searchCondition) + }else{ + alert("삭제를 실패하였습니다.") + } + } + ) + } + }); return (
    @@ -105,18 +129,19 @@ function List(props) {
    • - { - wrdRef.current.value = e.target.value; - }} - /> - + {setSearchCondition({...searchCondition, searchKeyword: e.target.value})}}/> +
    @@ -156,15 +175,7 @@ function List(props) {
    - { - retrieveList({ - ...searchCondition, - pageIndex: passedPage, - searchCnd: cndRef.current.value, - searchWrd: wrdRef.current.value - }) - }} /> + {movePage(passedPage)}} />
    diff --git a/egovframe-template-simple-react-contribution/src/pages/admin/users/UserInfoModal.jsx b/egovframe-template-simple-react-contribution/src/pages/admin/users/UserInfoModal.jsx index cbd178d..c1e661a 100644 --- a/egovframe-template-simple-react-contribution/src/pages/admin/users/UserInfoModal.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/admin/users/UserInfoModal.jsx @@ -1,14 +1,17 @@ -import React, {useEffect, useState} from "react" +import React, {useCallback, useEffect, useState} from "react" import Modal from "react-bootstrap/Modal"; -import * as EgovNet from "../../../api/egovFetch"; +import * as EgovNet from "api/egovFetch"; import Form from "react-bootstrap/Form"; import Row from "react-bootstrap/Row"; import Col from "react-bootstrap/Col"; import Button from "react-bootstrap/Button"; +import SelectOption from "components/commonCode/SelectOption"; +import CheckBox from "components/commonCode/CheckBox"; +import CODE from "../../../constants/code"; -function UserInfoModal({userSeq}){ +function UserInfoModal({userSeq, reloadFunction}){ - const [userInfo, setUserInfo] = useState({ userId: '', password: '', passwordChk: '', userNm: '', email: '', phoneNum: ''}); + const [userInfo, setUserInfo] = useState({ userSeq: '', userId: '', password: '', passwordChk: '', userNm: '', email: '', phoneNum: '', userSe:'', userRole:'', status:''}); function getModalContent(){ EgovNet.requestFetch( @@ -17,15 +20,20 @@ function UserInfoModal({userSeq}){ method: "GET" }, (resp) => { - const respInfo = { - userId: resp.result.userInfo.userId, - userNm: resp.result.userInfo.userNm, - email: resp.result.userInfo.email, - phoneNum: resp.result.userInfo.phoneNum, + const respInfo = resp.result.userInfo; + const info = { + userSeq: respInfo.userSeq, + userId: respInfo.userId, + userNm: respInfo.userNm, + email: respInfo.email, + phoneNum: respInfo.phoneNum, password: "", passwordChk: "", + userSe: respInfo.userSe, + userRole: respInfo.userRole, + status: respInfo.status } - setUserInfo(respInfo); + setUserInfo(info); }, (resp) => { console.log("err response : ", resp); @@ -33,8 +41,51 @@ function UserInfoModal({userSeq}){ ); } - function userInfoChange(){ - + function userInfoChange(e){ + e.preventDefault(); + e.stopPropagation(); + const form = e.target; + const info = { + userSeq: form.userSeq.value, + userId: form.userId.value, + password: form.password.value, + passwordChk: form.passwordChk.value, + userNm: form.userNm.value, + email: form.email.value, + phoneNum: form.phoneNum.value, + userSe: form.userSe.value, + userRole: '', + status: form.status.value, + } + let userRole = ''; + form.userRole.forEach(function (input){ + if(input.checked){ + userRole += input.value+',' + } + }) + if(userRole){ + info.userRole = userRole.slice(0, -1) + } + EgovNet.requestFetch( + '/admin/users/info', + { + method: "PUT", + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify(info) + }, + (resp) => { + if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { + alert("저장되었습니다.") + reloadFunction(); + }else if(Number(resp.resultCode) === Number(CODE.RCV_ERROR_AUTH)){ + console.log("토큰 갱신중.") + }else{ + alert(resp.result.resultMessage) + } + } + ) } useEffect(() => { @@ -43,89 +94,84 @@ function UserInfoModal({userSeq}){ return ( <> - + {userInfo.userNm} 상세정보 -
    - + {userInfoChange(e)}} noValidate> + + 아이디 - setUserInfo({ ...userInfo, userId: e.target.value })}/> + - - - 이름 - - - setUserInfo({ ...userInfo, userNm: e.target.value })}/> - - - - - 이메일 - - - setUserInfo({ ...userInfo, email: e.target.value })}/> - - - - - 연락처 - - - setUserInfo({ ...userInfo, phoneNum: e.target.value })}/> - - - + 비밀번호 - setUserInfo({ ...userInfo, password: e.target.value })}/> + - + 비밀번호 확인 - setUserInfo({ ...userInfo, passwordChk: e.target.value })}/> + - + + + 이름 + + + + + + + + 이메일 + + + + + + + + 연락처 + + + + + + 사용자 유형 - + - + 사용자 권한 - + - + 상태 - + diff --git a/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx b/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx index 236a078..e2c893d 100644 --- a/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/login/EgovLoginContent.jsx @@ -5,6 +5,7 @@ import {parseJwt} from "../../utils/parseJwt"; import URL from 'constants/url'; import CODE from 'constants/code'; +import Form from "react-bootstrap/Form"; import Row from 'react-bootstrap/Row'; import Col from 'react-bootstrap/Col'; import Modal from "react-bootstrap/Modal"; @@ -55,10 +56,8 @@ function EgovLoginContent(props) { if (idFlag === false) { setLocalItem(KEY_ID, ""); - checkRef.current.className = "f_chk" } else { - checkRef.current.className = "f_chk on" - }; + } }, []); useEffect(() => { @@ -143,9 +142,11 @@ function EgovLoginContent(props) { - */} ID 찾기 diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/committee/schedules/service/impl/EgovIndvdlSchdulManageServiceImpl.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/committee/schedules/service/impl/EgovIndvdlSchdulManageServiceImpl.java index 10eeeff..902b9a0 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/committee/schedules/service/impl/EgovIndvdlSchdulManageServiceImpl.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/committee/schedules/service/impl/EgovIndvdlSchdulManageServiceImpl.java @@ -3,27 +3,18 @@ package com.dbnt.kcscbackend.admin.committee.schedules.service.impl; import com.dbnt.kcscbackend.admin.committee.schedules.model.CreateScheduleVO; import com.dbnt.kcscbackend.admin.committee.schedules.service.EgovIndvdlSchdulManageService; -import com.dbnt.kcscbackend.admin.config.repository.TcCodeItemRepository; -import com.dbnt.kcscbackend.admin.config.repository.TnCmtEventRepository; -import com.dbnt.kcscbackend.admin.config.repository.TnCmtOrgRepository; import com.dbnt.kcscbackend.auth.entity.LoginVO; +import com.dbnt.kcscbackend.commonCode.entity.TnCmtEvent; import com.dbnt.kcscbackend.config.common.ResponseCode; +import com.dbnt.kcscbackend.commonCode.repository.TcCodeItemRepository; +import com.dbnt.kcscbackend.commonCode.repository.TnCmtEventRepository; +import com.dbnt.kcscbackend.commonCode.repository.TnCmtOrgRepository; import com.dbnt.kcscbackend.config.common.ResultVO; import lombok.RequiredArgsConstructor; -import org.apache.tomcat.util.json.JSONParser; import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl; -import org.springframework.boot.configurationprocessor.json.JSONObject; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; -import java.sql.Timestamp; -import java.text.SimpleDateFormat; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.ZoneId; import java.util.*; import java.util.stream.Collectors; @@ -129,14 +120,14 @@ public class EgovIndvdlSchdulManageServiceImpl extends EgovAbstractServiceImpl i Map response = tnCmtEventRepository.spAddTnCmtEvent( - createScheduleVO.getDivMeet(), - createScheduleVO.getUpCommittee(), - createScheduleVO.getCommittee(), - createScheduleVO.getTitle(), - createScheduleVO.getLocation(), - createScheduleVO.getContents(), - createScheduleVO.getStartDate(), - createScheduleVO.getEndDate(), + createScheduleVO.getDivMeet(), // 구분 + createScheduleVO.getUpCommittee(), // 심의위원회 상위 코드 번호 + createScheduleVO.getCommittee(), // 심의위원회 하위 코드 번호 + createScheduleVO.getTitle(), // 제목 + createScheduleVO.getLocation(), // 장소 + createScheduleVO.getContents(), // 내용 + createScheduleVO.getStartDate(), // 날짜/시간의 시작 일시 + createScheduleVO.getEndDate(), // 날짜/시간의 종료 일시 "admin", null, null, @@ -168,10 +159,28 @@ public class EgovIndvdlSchdulManageServiceImpl extends EgovAbstractServiceImpl i ); - int isValid = tnCmtEventRepository.sp_is_valid_tn_cmt_event_id( scheduleId ); + int isValid = tnCmtEventRepository.sp_is_valid_tn_cmt_event_id( scheduleId.intValue() ); + + if( isValid == 0 ) { + throw new Exception("대상이 존재하지 않습니다."); + } + + TnCmtEvent tnCmtEvent = tnCmtEventRepository.findByEvtSeq(scheduleId); Map dto = new HashMap(); - //dto.put("schdulId", response.get("_evt_seq") ); + dto.put("evtSeq", tnCmtEvent.getEvtSeq()); // sequence + dto.put("divMeet", tnCmtEvent.getEvtType()); // 구분 + dto.put("upCommittee", tnCmtEvent.getUpCmtSeq()); // 심의위원회 상위 코드 번호 + dto.put("committee", tnCmtEvent.getCmtSeq()); // 심의위원회 하위 코드 번호 + dto.put("title", tnCmtEvent.getEvtTitle()); // 제목 + dto.put("location", tnCmtEvent.getEvtLocation()); // 장소 + dto.put("contents", tnCmtEvent.getEvtContents()); // 내용 + dto.put("startDate", tnCmtEvent.getEvtStartDt()); // 날짜/시간의 시작 일시 + dto.put("endDate", tnCmtEvent.getEvtEndDt()); // 날짜/시간의 종료 일시 + + // 문자열로 리턴하도록 수정해야 함. + + resultVO.setResult(dto); resultVO.setResultCode(ResponseCode.SUCCESS.getCode()); diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/AdminConfigController.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/AdminConfigController.java index 48b889d..9868803 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/AdminConfigController.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/AdminConfigController.java @@ -1,7 +1,7 @@ package com.dbnt.kcscbackend.admin.config; -import com.dbnt.kcscbackend.admin.config.entity.TcCodeGrp; -import com.dbnt.kcscbackend.admin.config.entity.TcCodeItem; +import com.dbnt.kcscbackend.commonCode.entity.TcCodeGrp; +import com.dbnt.kcscbackend.commonCode.entity.TcCodeItem; import com.dbnt.kcscbackend.admin.config.service.AdminConfigService; import com.dbnt.kcscbackend.auth.entity.LoginVO; import com.dbnt.kcscbackend.config.common.BaseController; @@ -44,7 +44,7 @@ public class AdminConfigController extends BaseController { public ResultVO getCodeGrp() throws Exception{ ResultVO resultVO = new ResultVO(); Map resultMap = new HashMap<>(); - resultMap.put("codeGrpList", adminConfigService.selectCodeGrpList()); + resultMap.put("codeGrpList", adminConfigService.selectCodeGrpList()); resultVO.setResult(resultMap); return resultVO; } @@ -215,4 +215,21 @@ public class AdminConfigController extends BaseController { return resultVO; } + @Operation( + summary = "메뉴 조회", + description = "메뉴 조회", + tags = {"AdminConfigController"} + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "조회 성공"), + @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님") + }) + @RequestMapping(method = RequestMethod.GET, value = "/menu-mgt") + public ResultVO getMenuMgt(){ + ResultVO resultVO = new ResultVO(); + Map resultMap = new HashMap<>(); + resultMap.put("menuList", adminConfigService.selectMenuList()); + resultVO.setResult(resultMap); + return resultVO; + } } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TcMenu.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TcMenu.java new file mode 100644 index 0000000..754939b --- /dev/null +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TcMenu.java @@ -0,0 +1,53 @@ +package com.dbnt.kcscbackend.admin.config.entity; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.LocalDateTime; + +@Getter +@Setter +@Entity +@NoArgsConstructor +@DynamicInsert +@DynamicUpdate +@Table(name = "tc_menu") +public class TcMenu { + @Id + @Column(name = "menu_id") + private String menuId; + @Column(name = "role_grp_id") + private String roleGrpId; + @Column(name = "menu_title") + private String menuTitle; + @Column(name = "menu_group") + private String menuGroup; + @Column(name = "menu_level") + private String menuLevel; + @Column(name = "menu_sort") + private String menuSort; + @Column(name = "menu_url") + private String menuUrl; + @Column(name = "menu_type_cd") + private String menuTypeCd; + @Column(name = "frst_crt_id") + private String frstCrtId; + @Column(name = "frst_crt_dt") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime frstCrtDt; + @Column(name = "last_chg_id") + private String lastChgId; + @Column(name = "last_chg_dt") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime lastChgDt; + @Column(name = "use_yn") + private String useYn; +} diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TcMenuRepository.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TcMenuRepository.java new file mode 100644 index 0000000..31a5fa3 --- /dev/null +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TcMenuRepository.java @@ -0,0 +1,10 @@ +package com.dbnt.kcscbackend.admin.config.repository; + +import com.dbnt.kcscbackend.admin.config.entity.TcMenu; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface TcMenuRepository extends JpaRepository { + List findByUseYnOrderByMenuIdAsc(String useYn); +} diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/service/AdminConfigService.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/service/AdminConfigService.java index e42a300..9e25549 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/service/AdminConfigService.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/service/AdminConfigService.java @@ -1,9 +1,11 @@ package com.dbnt.kcscbackend.admin.config.service; -import com.dbnt.kcscbackend.admin.config.entity.TcCodeGrp; -import com.dbnt.kcscbackend.admin.config.entity.TcCodeItem; -import com.dbnt.kcscbackend.admin.config.repository.TcCodeGrpRepository; -import com.dbnt.kcscbackend.admin.config.repository.TcCodeItemRepository; +import com.dbnt.kcscbackend.admin.config.entity.TcMenu; +import com.dbnt.kcscbackend.admin.config.repository.TcMenuRepository; +import com.dbnt.kcscbackend.commonCode.entity.TcCodeGrp; +import com.dbnt.kcscbackend.commonCode.entity.TcCodeItem; +import com.dbnt.kcscbackend.commonCode.repository.TcCodeGrpRepository; +import com.dbnt.kcscbackend.commonCode.repository.TcCodeItemRepository; import lombok.RequiredArgsConstructor; import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl; import org.springframework.stereotype.Service; @@ -17,6 +19,7 @@ public class AdminConfigService extends EgovAbstractServiceImpl { private final TcCodeGrpRepository codeGrpRepository; private final TcCodeItemRepository codeItemRepository; + private final TcMenuRepository menuRepository; public List selectCodeGrpList(){ return codeGrpRepository.findByUseYn("Y"); @@ -95,4 +98,8 @@ public class AdminConfigService extends EgovAbstractServiceImpl { return "validGrpCd"; } } + + public List selectMenuList() { + return menuRepository.findByUseYnOrderByMenuIdAsc("Y"); + } } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/AdminLogsController.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/AdminLogsController.java index 568959f..44b6f23 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/AdminLogsController.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/AdminLogsController.java @@ -1,7 +1,10 @@ package com.dbnt.kcscbackend.admin.logs; +import com.dbnt.kcscbackend.admin.logs.entity.TnDailyMenuLog; import com.dbnt.kcscbackend.admin.logs.entity.ThPrivacyLog; +import com.dbnt.kcscbackend.admin.logs.service.AdminMenuService; import com.dbnt.kcscbackend.admin.logs.service.AdminLogsService; +import com.dbnt.kcscbackend.admin.logs.service.AdminUserService; import com.dbnt.kcscbackend.auth.entity.LoginVO; import com.dbnt.kcscbackend.config.common.BaseController; import com.dbnt.kcscbackend.config.common.ResponseCode; @@ -11,17 +14,16 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.egovframe.rte.fdl.property.EgovPropertyService; -import org.egovframe.rte.ptl.mvc.tags.ui.pagination.PaginationInfo; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.*; + +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.util.Date; -import javax.annotation.Resource; import java.util.HashMap; +import java.util.List; import java.util.Map; @RestController @@ -30,20 +32,76 @@ import java.util.Map; @Tag(name="AdminLogsController", description = "사이트관리 로그현황 메뉴 컨트롤러") public class AdminLogsController extends BaseController { - @Resource(name = "propertiesService") - protected EgovPropertyService propertyService; - + private final AdminMenuService adminMenuService; + private final AdminUserService adminUserService; private final AdminLogsService adminLogsService; @Operation( - summary = "로그현황 - 개인정보 로그", - description = "개인정보 로그현황", + summary = "로그현황 - 메뉴별 접속현황", + description = "메뉴별 접속현황", tags = {"AdminLogsController"} ) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "조회 성공"), @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님") }) + @RequestMapping(method = RequestMethod.POST, value = "/menu", consumes = MediaType.APPLICATION_JSON_VALUE) + public ResultVO MenuListCount(@RequestBody Map dateRange, + @AuthenticationPrincipal LoginVO user) + throws Exception { + + ResultVO resultVO = new ResultVO(); + Map resultMap = new HashMap<>(); + + String startDate = dateRange.get("start_date"); + String endDate = dateRange.get("end_date"); + + resultMap.put("resultCnt", adminMenuService.selectMenuCountCnt(startDate, endDate)); + resultMap.put("resultList", adminMenuService.selectMenuCount(startDate, endDate)); + resultVO.setResultCode(ResponseCode.SUCCESS.getCode()); + resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage()); + resultVO.setResult(resultMap); + return resultVO; + } + + + @Operation( + summary = "로그현황 - 사용자 접속현황", + description = "사용자 접속현황", + tags = {"AdminLogsController"} + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "조회 성공"), + @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님") + }) + @RequestMapping(method = RequestMethod.POST, value = "/user", consumes = MediaType.APPLICATION_JSON_VALUE) + public ResultVO UserListCount(@RequestBody Map dateRange, + @AuthenticationPrincipal LoginVO user) + throws Exception { + + ResultVO resultVO = new ResultVO(); + Map resultMap = new HashMap<>(); + + String startDate = dateRange.get("start_date"); + String endDate = dateRange.get("end_date"); + + resultMap.put("resultCnt", adminUserService.selectUserCountCnt(startDate, endDate)); + resultMap.put("resultList", adminUserService.selectUserCount(startDate, endDate)); + resultVO.setResultCode(ResponseCode.SUCCESS.getCode()); + resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage()); + resultVO.setResult(resultMap); + return resultVO; + } + + @Operation( + summary = "로그현황 - 개인정보 로그", + description = "개인정보 로그현황", + tags = {"AdminLogsController"} + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "조회 성공"), + @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님") + }) @RequestMapping(method = RequestMethod.POST, value = "/privacy", consumes = MediaType.APPLICATION_JSON_VALUE) public ResultVO selectPrivacyLogsList(@RequestBody ThPrivacyLog thPrivacyLog, @AuthenticationPrincipal LoginVO user) throws Exception { @@ -62,5 +120,4 @@ public class AdminLogsController extends BaseController { return resultVO; } - } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/entity/TnDailyMenuLog.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/entity/TnDailyMenuLog.java new file mode 100644 index 0000000..5fd0bd6 --- /dev/null +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/entity/TnDailyMenuLog.java @@ -0,0 +1,40 @@ +package com.dbnt.kcscbackend.admin.logs.entity; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import java.time.LocalDate; +import java.awt.*; + +@Getter +@Setter +@Accessors(chain = true) +@Entity +@NoArgsConstructor +@DynamicInsert +@DynamicUpdate +@Table(name = "tn_daily_menu_log") +public class TnDailyMenuLog { + @Id + @Column(name = "dml_seq") + private Long dmlSeq; + + @Column(name = "menu_id") + private String menuId; + + @Column(name = "menu_title") + private String menuTitle; + + @Column(name = "log_cnt") + private Long logCnt; + + @Column(name = "log_dt") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate logDt; +} diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/entity/TnDailyUserConnLog.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/entity/TnDailyUserConnLog.java new file mode 100644 index 0000000..9ae62a7 --- /dev/null +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/entity/TnDailyUserConnLog.java @@ -0,0 +1,34 @@ +package com.dbnt.kcscbackend.admin.logs.entity; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import java.time.LocalDate; +import java.awt.*; + +@Getter +@Setter +@Accessors(chain = true) +@Entity +@NoArgsConstructor +@DynamicInsert +@DynamicUpdate +@Table(name = "tn_daily_user_log") +public class TnDailyUserConnLog { + @Id + @Column(name = "dul_seq") + private Long dulSeq; + + @Column(name = "log_cnt") + private Long logCnt; + + @Column(name = "log_dt") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate logDt; +} diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/repository/MenuLogsRepository.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/repository/MenuLogsRepository.java new file mode 100644 index 0000000..0ea127a --- /dev/null +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/repository/MenuLogsRepository.java @@ -0,0 +1,26 @@ +package com.dbnt.kcscbackend.admin.logs.repository; + +import com.dbnt.kcscbackend.admin.logs.entity.TnDailyMenuLog; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.time.LocalDate; +import java.util.List; + +public interface MenuLogsRepository extends JpaRepository { + + @Query(value = "SELECT COUNT(DISTINCT menu_id) " + + "FROM tn_daily_menu_log " + + "WHERE log_dt BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD')", nativeQuery = true) + long countDistinctMenuIds(@Param("startDate") String startDate, @Param("endDate") String endDate); + + @Query(value = "SELECT menu_id, MAX(menu_title) as menu_title, sum(log_cnt) as log_cnt " + + "FROM tn_daily_menu_log " + + "WHERE log_dt BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD') " + + "GROUP BY menu_id " + + "ORDER BY log_cnt desc", nativeQuery = true) + List selectCountMenu(@Param("startDate") String startDate, @Param("endDate") String endDate); + + +} diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/repository/PrivacyLogsRepository.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/repository/PrivacyLogsRepository.java index aca2cb7..ad0fe00 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/repository/PrivacyLogsRepository.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/repository/PrivacyLogsRepository.java @@ -6,7 +6,5 @@ import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface PrivacyLogsRepository extends JpaRepository { - long count(); // 전체 레코드 수를 반환하는 메서드 - List findAllByOrderByUplSeqDesc(); } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/repository/UserLogsRepository.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/repository/UserLogsRepository.java new file mode 100644 index 0000000..8c8d67e --- /dev/null +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/repository/UserLogsRepository.java @@ -0,0 +1,25 @@ +package com.dbnt.kcscbackend.admin.logs.repository; + +import com.dbnt.kcscbackend.admin.logs.entity.TnDailyUserConnLog; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface UserLogsRepository extends JpaRepository { + + @Query(value = "SELECT COUNT(DISTINCT log_dt) " + + "FROM tn_daily_user_log " + + "WHERE log_dt BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD')", nativeQuery = true) + long countDistinctUserIds(@Param("startDate") String startDate, @Param("endDate") String endDate); + + @Query(value = "SELECT TO_CHAR(log_dt, 'YYYY-MM-DD') as log_dt, sum(log_cnt) as log_cnt " + + "FROM tn_daily_user_log " + + "WHERE log_dt BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD') " + + "GROUP BY TO_CHAR(log_dt, 'YYYY-MM-DD') " + + "ORDER BY log_dt asc", nativeQuery = true) + List selectCountUser(@Param("startDate") String startDate, @Param("endDate") String endDate); + + +} diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/service/AdminLogsService.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/service/AdminLogsService.java index 11ad845..97db4df 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/service/AdminLogsService.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/service/AdminLogsService.java @@ -16,9 +16,6 @@ public class AdminLogsService extends EgovAbstractServiceImpl { private final PrivacyLogsRepository privacyLogsRepository; -// public List selectPrivacyList(){ -// return privacyLogsRepository.findAll(); -// } public Map selectPrivacyList() { Map resultMap = new HashMap<>(); diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/service/AdminMenuService.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/service/AdminMenuService.java new file mode 100644 index 0000000..03f1f85 --- /dev/null +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/service/AdminMenuService.java @@ -0,0 +1,27 @@ +package com.dbnt.kcscbackend.admin.logs.service; + +import com.dbnt.kcscbackend.admin.logs.entity.TnDailyMenuLog; +import com.dbnt.kcscbackend.admin.logs.repository.MenuLogsRepository; +import lombok.RequiredArgsConstructor; +import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class AdminMenuService extends EgovAbstractServiceImpl { + private final MenuLogsRepository menuLogsRepository; + + // 메뉴별 접속횟수 + public List selectMenuCount(String startDate, String endDate) { + return menuLogsRepository.selectCountMenu(startDate, endDate); + } + + // 전체 레코드 수 가져오기 + public long selectMenuCountCnt(String startDate, String endDate) { + return menuLogsRepository.countDistinctMenuIds(startDate, endDate); + } + +} diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/service/AdminUserService.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/service/AdminUserService.java new file mode 100644 index 0000000..93980ed --- /dev/null +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/logs/service/AdminUserService.java @@ -0,0 +1,25 @@ +package com.dbnt.kcscbackend.admin.logs.service; + +import com.dbnt.kcscbackend.admin.logs.repository.UserLogsRepository; +import lombok.RequiredArgsConstructor; +import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class AdminUserService extends EgovAbstractServiceImpl { + private final UserLogsRepository userLogsRepository; + + // 메뉴별 접속횟수 + public List selectUserCount(String startDate, String endDate) { + return userLogsRepository.selectCountUser(startDate, endDate); + } + + // 전체 레코드 수 가져오기 + public long selectUserCountCnt(String startDate, String endDate) { + return userLogsRepository.countDistinctUserIds(startDate, endDate); + } + +} diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/AdminUsersController.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/AdminUsersController.java index 1c4247e..dbf5abc 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/AdminUsersController.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/AdminUsersController.java @@ -2,18 +2,26 @@ package com.dbnt.kcscbackend.admin.users; import com.dbnt.kcscbackend.admin.users.service.AdminUsersService; +import com.dbnt.kcscbackend.auth.entity.LoginVO; import com.dbnt.kcscbackend.auth.entity.UserInfo; import com.dbnt.kcscbackend.config.common.BaseController; +import com.dbnt.kcscbackend.config.common.ResponseCode; import com.dbnt.kcscbackend.config.common.ResultVO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import javax.validation.Valid; import java.util.HashMap; import java.util.Map; @@ -65,4 +73,65 @@ public class AdminUsersController extends BaseController { return resultVO; } + @Operation( + summary = "사용자 정보 수정", + description = "사용자 정보 수정", + tags = {"AdminUsersController"} + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "수정 성공"), + @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님") + }) + @RequestMapping(method = RequestMethod.PUT, value = "/info") + public ResultVO modifyUserInfo(@RequestBody @Valid UserInfo info, Errors errors, @AuthenticationPrincipal LoginVO user) throws Exception{ + ResultVO resultVO = new ResultVO(); + if(errors.hasErrors()){ + StringBuilder msg = new StringBuilder(); + for(FieldError error: errors.getFieldErrors()){ + msg.append(error.getDefaultMessage()); + msg.append("\n"); + } + resultVO.setResultCode(ResponseCode.INPUT_CHECK_ERROR.getCode()); + resultVO.setResultMessage(msg.toString()); + }else if(!info.getPassword().equals(info.getPasswordChk())){ + resultVO.setResultCode(ResponseCode.SAVE_ERROR.getCode()); + resultVO.setResultMessage("비밀번호 확인이 잘못 입력되었습니다."); + }else { + Integer insertResult = adminUsersService.updateUserInfo(info, user.getId()); + if(insertResult!=null){ + if(insertResult==-1){ + resultVO.setResultCode(ResponseCode.SAVE_ERROR.getCode()); + resultVO.setResultMessage("수정 대상이 존재하지 않습니다."); + }else if(insertResult==-2){ + resultVO.setResultCode(ResponseCode.SAVE_ERROR.getCode()); + resultVO.setResultMessage("가입된 이메일입니다."); + }else{ + resultVO.setResultCode(ResponseCode.SUCCESS.getCode()); + resultVO.setResultMessage("저장 되었습니다."); + } + }else{ + resultVO.setResultCode(ResponseCode.SAVE_ERROR.getCode()); + resultVO.setResultMessage("저장에 실패하였습니다."); + } + } + return resultVO; + } + + @Operation( + summary = "사용자 정보 삭제", + description = "사용자 정보 삭제", + tags = {"AdminUsersController"} + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "삭제 성공"), + @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님") + }) + @RequestMapping(method = RequestMethod.DELETE, value = "/info", consumes = MediaType.APPLICATION_JSON_VALUE) + public ResultVO deleteUserInfo(@RequestBody UserInfo info) throws Exception{ + ResultVO resultVO = new ResultVO(); + adminUsersService.deleteUserInfo(info.getUserSeq()); + resultVO.setResultCode(ResponseCode.SUCCESS.getCode()); + return resultVO; + } + } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/service/AdminUsersService.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/service/AdminUsersService.java index ec0f721..c5c7671 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/service/AdminUsersService.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/service/AdminUsersService.java @@ -4,13 +4,16 @@ import com.dbnt.kcscbackend.admin.users.mapper.AdminUsersMapper; import com.dbnt.kcscbackend.auth.entity.UserInfo; import com.dbnt.kcscbackend.auth.repository.UserInfoRepository; import lombok.RequiredArgsConstructor; +import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; import java.util.List; @Service @RequiredArgsConstructor -public class AdminUsersService { +public class AdminUsersService extends EgovAbstractServiceImpl { private final UserInfoRepository userInfoRepository; private final AdminUsersMapper usersMapper; @@ -28,4 +31,37 @@ public class AdminUsersService { info.setPassword(null); return info; } + + @Transactional + public Integer updateUserInfo(UserInfo info, String updateUser) { + UserInfo savedInfo = userInfoRepository.findById(info.getUserSeq()).orElse(null); + UserInfo emailChk = userInfoRepository.findByEmail(info.getEmail()).orElse(null); + if(savedInfo==null){ + return -1; + }else if(emailChk != null){ + if(!emailChk.getUserSeq().equals(info.getUserSeq())){ + return -2; + } + } + + savedInfo.setUserNm(info.getUserNm()); + if(!info.getPassword().isEmpty()){ + savedInfo.setPassword(info.convertPassword(info.getPassword())); + } + savedInfo.setEmail(info.getEmail()); + savedInfo.setPhoneNum(info.getPhoneNum()); + savedInfo.setUserSe(info.getUserSe()); + savedInfo.setUserRole(info.getUserRole()); + savedInfo.setStatus(info.getStatus()); + savedInfo.setLastChgId(updateUser); + savedInfo.setLastChgDt(LocalDateTime.now()); + + return savedInfo.getUserSeq(); + } + + @Transactional + public void deleteUserInfo(Integer userSeq) { + userInfoRepository.deleteById(userSeq); + } + } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/UserInfo.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/UserInfo.java index 869c47e..5e22327 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/UserInfo.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/UserInfo.java @@ -2,6 +2,7 @@ package com.dbnt.kcscbackend.auth.entity; import com.dbnt.kcscbackend.config.common.BoardParams; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -11,8 +12,12 @@ import org.springframework.format.annotation.DateTimeFormat; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder; import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Collection; @@ -32,16 +37,23 @@ public class UserInfo extends BoardParams implements UserDetails{ @Column(name = "user_seq") private Integer userSeq; @Column(name = "user_id") + @Pattern(regexp = "^[a-zA-Z]{1}[a-zA-Z0-9_]{4,11}$") + @NotBlank(message = "아이디를 입력해주세요.") private String userId; @Column(name = "password") private String password; @Column(name = "email") + @Email(message = "이메일 형식에 맞지 않습니다.") + @Schema(description = "이메일주소") + @NotBlank(message = "이메일을 입력해주세요.") private String email; @Column(name = "user_se") private String userSe; @Column(name = "user_nm") + @NotBlank(message = "이름을 입력해주세요.") private String userNm; @Column(name = "phone_num") + @NotBlank(message = "연락처를 입력해주세요.") private String phoneNum; @Column(name = "user_role") private String userRole; @@ -56,6 +68,9 @@ public class UserInfo extends BoardParams implements UserDetails{ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime lastChgDt; + @Transient + private String passwordChk; + @Override @JsonIgnore public Collection getAuthorities() { @@ -92,4 +107,11 @@ public class UserInfo extends BoardParams implements UserDetails{ return getStatus().equals("USE_ST"); } + + + public String convertPassword(String password){ + Pbkdf2PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder(); + return passwordEncoder.encode(password); + } + } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/impl/EgovLoginServiceImpl.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/impl/EgovLoginServiceImpl.java index 07d27aa..1f07ead 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/impl/EgovLoginServiceImpl.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/impl/EgovLoginServiceImpl.java @@ -59,7 +59,7 @@ public class EgovLoginServiceImpl extends EgovAbstractServiceImpl implements Ego } UserInfo info = new UserInfo(); info.setUserId(loginVO.getId()); - info.setPassword(convertPassword(loginVO.getPassword())); + info.setPassword(info.convertPassword(loginVO.getPassword())); info.setUserNm(loginVO.getUserNm()); info.setEmail(loginVO.getEmail()); info.setPhoneNum(loginVO.getPhoneNum()); @@ -85,7 +85,7 @@ public class EgovLoginServiceImpl extends EgovAbstractServiceImpl implements Ego int rdNum = rd.nextInt(95)+33; password.append((char)rdNum); } - user.setPassword(convertPassword(password.toString())); + user.setPassword(user.convertPassword(password.toString())); return password.toString(); } return null; @@ -184,9 +184,4 @@ public class EgovLoginServiceImpl extends EgovAbstractServiceImpl implements Ego return result; } - - private String convertPassword(String password){ - Pbkdf2PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder(); - return passwordEncoder.encode(password); - } } \ No newline at end of file diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/CommonCodeController.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/CommonCodeController.java new file mode 100644 index 0000000..9a49bb6 --- /dev/null +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/CommonCodeController.java @@ -0,0 +1,43 @@ +package com.dbnt.kcscbackend.commonCode; + +import com.dbnt.kcscbackend.commonCode.entity.TcCodeItem; +import com.dbnt.kcscbackend.commonCode.service.CommonCodeService; +import com.dbnt.kcscbackend.config.common.ResultVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/commonCode") +@Tag(name="CommonCodeController", description = "공통코드 컨트롤러") +public class CommonCodeController { + + private final CommonCodeService commonCodeService; + + @Operation( + summary = "코드 아이템 목록 조회", + description = "코드 아이템 목록 조회", + tags = {"CommonCodeController"} + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "조회 성공"), + @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님") + }) + @RequestMapping(method = RequestMethod.GET, value = "/code-item") + public ResultVO getCodeItemList(TcCodeItem codeItem) throws Exception{ + ResultVO resultVO = new ResultVO(); + Map resultMap = new HashMap<>(); + resultMap.put("codeList", commonCodeService.selectCodeItemList(codeItem.getGrpCd())); + resultVO.setResult(resultMap); + return resultVO; + } +} diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TcCodeGrp.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TcCodeGrp.java similarity index 95% rename from kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TcCodeGrp.java rename to kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TcCodeGrp.java index b3255b3..53077eb 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TcCodeGrp.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TcCodeGrp.java @@ -1,4 +1,4 @@ -package com.dbnt.kcscbackend.admin.config.entity; +package com.dbnt.kcscbackend.commonCode.entity; import lombok.Getter; import lombok.NoArgsConstructor; diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TcCodeItem.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TcCodeItem.java similarity index 96% rename from kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TcCodeItem.java rename to kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TcCodeItem.java index f263d04..4b76f7a 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TcCodeItem.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TcCodeItem.java @@ -1,4 +1,4 @@ -package com.dbnt.kcscbackend.admin.config.entity; +package com.dbnt.kcscbackend.commonCode.entity; import lombok.*; import org.hibernate.annotations.DynamicInsert; diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TnCmtEvent.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TnCmtEvent.java similarity index 71% rename from kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TnCmtEvent.java rename to kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TnCmtEvent.java index 7d87372..937c901 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TnCmtEvent.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TnCmtEvent.java @@ -1,4 +1,4 @@ -package com.dbnt.kcscbackend.admin.config.entity; +package com.dbnt.kcscbackend.commonCode.entity; import lombok.*; import org.hibernate.annotations.DynamicInsert; @@ -21,57 +21,57 @@ public class TnCmtEvent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "evt_seq") - private Long evt_seq; + private Long evtSeq; @Column(name = "evt_type") - private String evt_type; + private String evtType; @Column(name = "up_cmt_seq") - private Long up_cmt_seq; + private Long upCmtSeq; @Column(name = "cmt_seq") - private Long cmt_seq; + private Long cmtSeq; @Column(name = "evt_title") - private String evt_title; + private String evtTitle; @Column(name = "evt_location") - private String evt_location; + private String evtLocation; @Column(name = "evt_contents") - private String evt_contents; + private String evtContents; @Column(name = "evt_start_dt") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime evt_start_dt; + private LocalDateTime evtStartDt; @Column(name = "evt_end_dt") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime evt_end_dt; + private LocalDateTime evtEndDt; @Column(name = "frst_crt_id") - private String frst_crt_id; + private String frstCrtId; @Column(name = "frst_crt_dt") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime frst_crt_dt; + private LocalDateTime frstCrtDt; @Column(name = "last_chg_id") - private String last_chg_id; + private String lastChgId; @Column(name = "last_chg_dt") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime last_chg_dt; + private LocalDateTime lastChgDt; @Column(name = "use_yn") - private String use_yn; + private String useYn; @Embeddable @Data @NoArgsConstructor @AllArgsConstructor public static class TnCmtEventId implements Serializable { - private Long evt_seq; + private Long evtSeq; } } \ No newline at end of file diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TnCmtOrg.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TnCmtOrg.java similarity index 96% rename from kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TnCmtOrg.java rename to kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TnCmtOrg.java index e2ec1a7..8e83ee1 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/entity/TnCmtOrg.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/entity/TnCmtOrg.java @@ -1,4 +1,4 @@ -package com.dbnt.kcscbackend.admin.config.entity; +package com.dbnt.kcscbackend.commonCode.entity; import lombok.*; import org.hibernate.annotations.DynamicInsert; diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TcCodeGrpRepository.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/repository/TcCodeGrpRepository.java similarity index 65% rename from kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TcCodeGrpRepository.java rename to kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/repository/TcCodeGrpRepository.java index 38b0492..40883a2 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TcCodeGrpRepository.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/repository/TcCodeGrpRepository.java @@ -1,6 +1,6 @@ -package com.dbnt.kcscbackend.admin.config.repository; +package com.dbnt.kcscbackend.commonCode.repository; -import com.dbnt.kcscbackend.admin.config.entity.TcCodeGrp; +import com.dbnt.kcscbackend.commonCode.entity.TcCodeGrp; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TcCodeItemRepository.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/repository/TcCodeItemRepository.java similarity index 70% rename from kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TcCodeItemRepository.java rename to kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/repository/TcCodeItemRepository.java index 5852f71..e5d507c 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TcCodeItemRepository.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/repository/TcCodeItemRepository.java @@ -1,6 +1,6 @@ -package com.dbnt.kcscbackend.admin.config.repository; +package com.dbnt.kcscbackend.commonCode.repository; -import com.dbnt.kcscbackend.admin.config.entity.TcCodeItem; +import com.dbnt.kcscbackend.commonCode.entity.TcCodeItem; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TnCmtEventRepository.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/repository/TnCmtEventRepository.java similarity index 88% rename from kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TnCmtEventRepository.java rename to kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/repository/TnCmtEventRepository.java index 4cc3627..5a0fab3 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/repository/TnCmtEventRepository.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/commonCode/repository/TnCmtEventRepository.java @@ -1,24 +1,21 @@ -package com.dbnt.kcscbackend.admin.config.repository; +package com.dbnt.kcscbackend.commonCode.repository; -import com.dbnt.kcscbackend.admin.config.entity.TnCmtEvent; -import com.dbnt.kcscbackend.admin.config.entity.TnCmtOrg; -import com.fasterxml.jackson.annotation.JsonFormat; + +import com.dbnt.kcscbackend.commonCode.entity.TnCmtEvent; +import com.dbnt.kcscbackend.commonCode.entity.TnCmtOrg; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.query.Procedure; import org.springframework.data.repository.query.Param; -import org.springframework.format.annotation.DateTimeFormat; import org.springframework.transaction.annotation.Transactional; -import java.sql.Timestamp; -import java.time.LocalDate; -import java.time.LocalDateTime; import java.util.Date; import java.util.List; import java.util.Map; + public interface TnCmtEventRepository extends JpaRepository { @Transactional @@ -85,7 +82,7 @@ public interface TnCmtEventRepository extends JpaRepository sp_is_valid_tn_cmt_event_id( @Param("_evt_seq") Long evtSeq ); @Procedure - int sp_is_valid_tn_cmt_event_id( Long evtSeq ); + int sp_is_valid_tn_cmt_event_id( Integer evtSeq ); @Query(value = "CALL sp_is_valid_tn_cmt_event_id ( :_evt_seq )", nativeQuery = true) @@ -95,5 +92,9 @@ public interface TnCmtEventRepository extends JpaRepository selectCodeItemList(String grpCd) { + return codeItemRepository.findByGrpCdAndUseYnOrderByGrpOrder(grpCd, "Y"); + } +} diff --git a/kcsc-back-end/src/main/resources/application-local.properties b/kcsc-back-end/src/main/resources/application-local.properties index e8d6360..ffcfe5b 100644 --- a/kcsc-back-end/src/main/resources/application-local.properties +++ b/kcsc-back-end/src/main/resources/application-local.properties @@ -13,8 +13,8 @@ spring.datasource.hikari.maximum-pool-size=4 #spring.datasource.username=kcsc #spring.datasource.password=dbnt0928! spring.datasource.driverClassName=net.sf.log4jdbc.sql.jdbcapi.DriverSpy -spring.datasource.url=jdbc:log4jdbc:postgresql://127.0.0.1:5432/kcsc -#spring.datasource.url=jdbc:log4jdbc:postgresql://118.219.150.34:50503/kcsc +#spring.datasource.url=jdbc:log4jdbc:postgresql://127.0.0.1:5432/kcsc +spring.datasource.url=jdbc:log4jdbc:postgresql://118.219.150.34:50503/kcsc spring.datasource.username=dbnt0031 spring.datasource.password=dbnt0928! diff --git a/kcsc-back-end/src/main/resources/mybatisMapper/AdminUsersMapper.xml b/kcsc-back-end/src/main/resources/mybatisMapper/AdminUsersMapper.xml index b6c4ac2..60cc896 100644 --- a/kcsc-back-end/src/main/resources/mybatisMapper/AdminUsersMapper.xml +++ b/kcsc-back-end/src/main/resources/mybatisMapper/AdminUsersMapper.xml @@ -31,17 +31,19 @@ and user_se = #{userSe} - - and user_id like '%'||#{searchKeyword}||'%' - - - and user_nm like '%'||#{searchKeyword}||'%' - - - and email like '%'||#{searchKeyword}||'%' - - - and phone_num like '%'||#{searchKeyword}||'%' + + + and user_id like '%'||#{searchKeyword}||'%' + + + and user_nm like '%'||#{searchKeyword}||'%' + + + and email like '%'||#{searchKeyword}||'%' + + + and phone_num like '%'||#{searchKeyword}||'%' +