front-boilerplate 설정

This commit is contained in:
hyojin 2023-09-06 14:00:01 +09:00
parent 4f6510a031
commit 3a639e9a38
26 changed files with 262 additions and 142 deletions

8
.prettierrc Normal file
View File

@ -0,0 +1,8 @@
{
"singleQuote": true,
"semi": true,
"useTabs": false,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 80
}

132
package-lock.json generated
View File

@ -1,24 +1,18 @@
{ {
"name": "tuya-admin-front-2", "name": "front-boilerplate",
"version": "0.1.0", "version": "0.0.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "tuya-admin-front-2", "name": "front-boilerplate",
"version": "0.1.0", "version": "0.0.1",
"dependencies": { "dependencies": {
"@sdt/sdt-ui-kit": "^0.1.17", "@sdt/sdt-ui-kit": "^0.1.20",
"@tanstack/react-query": "^4.33.0", "@tanstack/react-query": "^4.33.0",
"@tanstack/react-query-devtools": "^4.33.0",
"@types/lodash": "^4.14.197",
"@types/node": "20.5.1",
"@types/qs": "^6.9.7",
"@types/react": "18.2.20",
"@types/react-dom": "18.2.7",
"@types/react-modal": "^3.16.0",
"autoprefixer": "10.4.15", "autoprefixer": "10.4.15",
"axios": "^1.4.0", "axios": "^1.4.0",
"cookies-next": "^3.0.0",
"eslint": "8.47.0", "eslint": "8.47.0",
"eslint-config-next": "13.4.19", "eslint-config-next": "13.4.19",
"lodash": "^4.17.21", "lodash": "^4.17.21",
@ -36,6 +30,13 @@
"zustand": "^4.4.1" "zustand": "^4.4.1"
}, },
"devDependencies": { "devDependencies": {
"@tanstack/react-query-devtools": "^4.33.0",
"@types/lodash": "^4.14.197",
"@types/node": "20.5.1",
"@types/qs": "^6.9.7",
"@types/react": "18.2.20",
"@types/react-dom": "18.2.7",
"@types/react-modal": "^3.16.0",
"@typescript-eslint/eslint-plugin": "^6.4.1", "@typescript-eslint/eslint-plugin": "^6.4.1",
"@typescript-eslint/parser": "^6.4.1", "@typescript-eslint/parser": "^6.4.1",
"eslint-config-next": "13.4.19", "eslint-config-next": "13.4.19",
@ -3138,9 +3139,9 @@
"dev": true "dev": true
}, },
"node_modules/@sdt/sdt-ui-kit": { "node_modules/@sdt/sdt-ui-kit": {
"version": "0.1.17", "version": "0.1.20",
"resolved": "http://192.168.1.232:8081/repository/npm-hosted/@sdt/sdt-ui-kit/-/sdt-ui-kit-0.1.17.tgz", "resolved": "http://192.168.1.232:8081/repository/npm-hosted/@sdt/sdt-ui-kit/-/sdt-ui-kit-0.1.20.tgz",
"integrity": "sha512-jf8xCO+Dlo/pMMXQxmXFzwguCYKEIgsBg1knZ/XWScAKvnQfpABEB3jo9+vAvEQ+gdteg2L+xIcuaCceJk/NAQ==", "integrity": "sha512-vqRWbeDioEGgvgT2lDsQl13kPT/pX8N0NMk9FqN9W6+UIT/ZNP/uDvmVqnJyjQmC+xd5j/yJ5hwkuP0joVfqEQ==",
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
@ -3176,6 +3177,7 @@
"version": "8.8.4", "version": "8.8.4",
"resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.8.4.tgz", "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.8.4.tgz",
"integrity": "sha512-rKH8LjZiszWEvmi01NR72QWZ8m4xmXre0OOwlRGnjU01Eqz/QnN+cqpty2PJ0efHblq09+KilvyR7lsbzmXVEw==", "integrity": "sha512-rKH8LjZiszWEvmi01NR72QWZ8m4xmXre0OOwlRGnjU01Eqz/QnN+cqpty2PJ0efHblq09+KilvyR7lsbzmXVEw==",
"dev": true,
"dependencies": { "dependencies": {
"remove-accents": "0.4.2" "remove-accents": "0.4.2"
}, },
@ -3226,6 +3228,7 @@
"version": "4.33.0", "version": "4.33.0",
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.33.0.tgz", "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.33.0.tgz",
"integrity": "sha512-6gegkuDmOoiY5e6ZKj1id48vlCXchjfE/6tIpYO8dFlVMQ7t1bYna/Ce6qQJ69+kfEHbYiTTn2lj+FDjIBH7Hg==", "integrity": "sha512-6gegkuDmOoiY5e6ZKj1id48vlCXchjfE/6tIpYO8dFlVMQ7t1bYna/Ce6qQJ69+kfEHbYiTTn2lj+FDjIBH7Hg==",
"dev": true,
"dependencies": { "dependencies": {
"@tanstack/match-sorter-utils": "^8.7.0", "@tanstack/match-sorter-utils": "^8.7.0",
"superjson": "^1.10.0", "superjson": "^1.10.0",
@ -3326,12 +3329,14 @@
"node_modules/@types/lodash": { "node_modules/@types/lodash": {
"version": "4.14.197", "version": "4.14.197",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz",
"integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==" "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==",
"dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.5.1", "version": "20.5.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz",
"integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==" "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==",
"dev": true
}, },
"node_modules/@types/parse-json": { "node_modules/@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
@ -3346,7 +3351,8 @@
"node_modules/@types/qs": { "node_modules/@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
"dev": true
}, },
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "18.2.20", "version": "18.2.20",
@ -3362,6 +3368,7 @@
"version": "18.2.7", "version": "18.2.7",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz",
"integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==",
"dev": true,
"dependencies": { "dependencies": {
"@types/react": "*" "@types/react": "*"
} }
@ -3386,6 +3393,7 @@
"version": "3.16.0", "version": "3.16.0",
"resolved": "https://registry.npmjs.org/@types/react-modal/-/react-modal-3.16.0.tgz", "resolved": "https://registry.npmjs.org/@types/react-modal/-/react-modal-3.16.0.tgz",
"integrity": "sha512-iphdqXAyUfByLbxJn5j6d+yh93dbMgshqGP0IuBeaKbZXx0aO+OXsvEkt6QctRdxjeM9/bR+Gp3h9F9djVWTQQ==", "integrity": "sha512-iphdqXAyUfByLbxJn5j6d+yh93dbMgshqGP0IuBeaKbZXx0aO+OXsvEkt6QctRdxjeM9/bR+Gp3h9F9djVWTQQ==",
"dev": true,
"dependencies": { "dependencies": {
"@types/react": "*" "@types/react": "*"
} }
@ -4262,10 +4270,39 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/cookies-next": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cookies-next/-/cookies-next-3.0.0.tgz",
"integrity": "sha512-VaSrsjQJ8yHnGAGulV9zJxBr7hrKJ/O2mo87evsGIMF7XvJI3AJNguevotx0Gek1MMMBkZvZNWu2JueSNoSKEQ==",
"dependencies": {
"@types/cookie": "^0.4.1",
"@types/node": "^16.10.2",
"cookie": "^0.4.0"
}
},
"node_modules/cookies-next/node_modules/@types/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
},
"node_modules/cookies-next/node_modules/@types/node": {
"version": "16.18.48",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.48.tgz",
"integrity": "sha512-mlaecDKQ7rIZrYD7iiKNdzFb6e/qD5I9U1rAhq+Fd+DWvYVs+G2kv74UFHmSOlg5+i/vF3XxuR522V4u8BqO+Q=="
},
"node_modules/cookies-next/node_modules/cookie": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/copy-anything": { "node_modules/copy-anything": {
"version": "3.0.5", "version": "3.0.5",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
"integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
"dev": true,
"dependencies": { "dependencies": {
"is-what": "^4.1.8" "is-what": "^4.1.8"
}, },
@ -6264,6 +6301,7 @@
"version": "4.1.15", "version": "4.1.15",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.15.tgz", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.15.tgz",
"integrity": "sha512-uKua1wfy3Yt+YqsD6mTUEa2zSi3G1oPlqTflgaPJ7z63vUGN5pxFpnQfeSLMFnJDEsdvOtkp1rUWkYjB4YfhgA==", "integrity": "sha512-uKua1wfy3Yt+YqsD6mTUEa2zSi3G1oPlqTflgaPJ7z63vUGN5pxFpnQfeSLMFnJDEsdvOtkp1rUWkYjB4YfhgA==",
"dev": true,
"engines": { "engines": {
"node": ">=12.13" "node": ">=12.13"
}, },
@ -7500,7 +7538,8 @@
"node_modules/remove-accents": { "node_modules/remove-accents": {
"version": "0.4.2", "version": "0.4.2",
"resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz", "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz",
"integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==" "integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==",
"dev": true
}, },
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.4", "version": "1.22.4",
@ -8041,6 +8080,7 @@
"version": "1.13.1", "version": "1.13.1",
"resolved": "https://registry.npmjs.org/superjson/-/superjson-1.13.1.tgz", "resolved": "https://registry.npmjs.org/superjson/-/superjson-1.13.1.tgz",
"integrity": "sha512-AVH2eknm9DEd3qvxM4Sq+LTCkSXE2ssfh1t11MHMXyYXFQyQ1HLgVvV+guLTsaQnJU3gnaVo34TohHPulY/wLg==", "integrity": "sha512-AVH2eknm9DEd3qvxM4Sq+LTCkSXE2ssfh1t11MHMXyYXFQyQ1HLgVvV+guLTsaQnJU3gnaVo34TohHPulY/wLg==",
"dev": true,
"dependencies": { "dependencies": {
"copy-anything": "^3.0.2" "copy-anything": "^3.0.2"
}, },
@ -10716,9 +10756,9 @@
"dev": true "dev": true
}, },
"@sdt/sdt-ui-kit": { "@sdt/sdt-ui-kit": {
"version": "0.1.17", "version": "0.1.20",
"resolved": "http://192.168.1.232:8081/repository/npm-hosted/@sdt/sdt-ui-kit/-/sdt-ui-kit-0.1.17.tgz", "resolved": "http://192.168.1.232:8081/repository/npm-hosted/@sdt/sdt-ui-kit/-/sdt-ui-kit-0.1.20.tgz",
"integrity": "sha512-jf8xCO+Dlo/pMMXQxmXFzwguCYKEIgsBg1knZ/XWScAKvnQfpABEB3jo9+vAvEQ+gdteg2L+xIcuaCceJk/NAQ==", "integrity": "sha512-vqRWbeDioEGgvgT2lDsQl13kPT/pX8N0NMk9FqN9W6+UIT/ZNP/uDvmVqnJyjQmC+xd5j/yJ5hwkuP0joVfqEQ==",
"requires": { "requires": {
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
@ -10749,6 +10789,7 @@
"version": "8.8.4", "version": "8.8.4",
"resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.8.4.tgz", "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.8.4.tgz",
"integrity": "sha512-rKH8LjZiszWEvmi01NR72QWZ8m4xmXre0OOwlRGnjU01Eqz/QnN+cqpty2PJ0efHblq09+KilvyR7lsbzmXVEw==", "integrity": "sha512-rKH8LjZiszWEvmi01NR72QWZ8m4xmXre0OOwlRGnjU01Eqz/QnN+cqpty2PJ0efHblq09+KilvyR7lsbzmXVEw==",
"dev": true,
"requires": { "requires": {
"remove-accents": "0.4.2" "remove-accents": "0.4.2"
} }
@ -10771,6 +10812,7 @@
"version": "4.33.0", "version": "4.33.0",
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.33.0.tgz", "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.33.0.tgz",
"integrity": "sha512-6gegkuDmOoiY5e6ZKj1id48vlCXchjfE/6tIpYO8dFlVMQ7t1bYna/Ce6qQJ69+kfEHbYiTTn2lj+FDjIBH7Hg==", "integrity": "sha512-6gegkuDmOoiY5e6ZKj1id48vlCXchjfE/6tIpYO8dFlVMQ7t1bYna/Ce6qQJ69+kfEHbYiTTn2lj+FDjIBH7Hg==",
"dev": true,
"requires": { "requires": {
"@tanstack/match-sorter-utils": "^8.7.0", "@tanstack/match-sorter-utils": "^8.7.0",
"superjson": "^1.10.0", "superjson": "^1.10.0",
@ -10864,12 +10906,14 @@
"@types/lodash": { "@types/lodash": {
"version": "4.14.197", "version": "4.14.197",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz",
"integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==" "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==",
"dev": true
}, },
"@types/node": { "@types/node": {
"version": "20.5.1", "version": "20.5.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz",
"integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==" "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==",
"dev": true
}, },
"@types/parse-json": { "@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
@ -10884,7 +10928,8 @@
"@types/qs": { "@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
"dev": true
}, },
"@types/react": { "@types/react": {
"version": "18.2.20", "version": "18.2.20",
@ -10900,6 +10945,7 @@
"version": "18.2.7", "version": "18.2.7",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz",
"integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==",
"dev": true,
"requires": { "requires": {
"@types/react": "*" "@types/react": "*"
} }
@ -10924,6 +10970,7 @@
"version": "3.16.0", "version": "3.16.0",
"resolved": "https://registry.npmjs.org/@types/react-modal/-/react-modal-3.16.0.tgz", "resolved": "https://registry.npmjs.org/@types/react-modal/-/react-modal-3.16.0.tgz",
"integrity": "sha512-iphdqXAyUfByLbxJn5j6d+yh93dbMgshqGP0IuBeaKbZXx0aO+OXsvEkt6QctRdxjeM9/bR+Gp3h9F9djVWTQQ==", "integrity": "sha512-iphdqXAyUfByLbxJn5j6d+yh93dbMgshqGP0IuBeaKbZXx0aO+OXsvEkt6QctRdxjeM9/bR+Gp3h9F9djVWTQQ==",
"dev": true,
"requires": { "requires": {
"@types/react": "*" "@types/react": "*"
} }
@ -11505,10 +11552,38 @@
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
}, },
"cookies-next": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cookies-next/-/cookies-next-3.0.0.tgz",
"integrity": "sha512-VaSrsjQJ8yHnGAGulV9zJxBr7hrKJ/O2mo87evsGIMF7XvJI3AJNguevotx0Gek1MMMBkZvZNWu2JueSNoSKEQ==",
"requires": {
"@types/cookie": "^0.4.1",
"@types/node": "^16.10.2",
"cookie": "^0.4.0"
},
"dependencies": {
"@types/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
},
"@types/node": {
"version": "16.18.48",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.48.tgz",
"integrity": "sha512-mlaecDKQ7rIZrYD7iiKNdzFb6e/qD5I9U1rAhq+Fd+DWvYVs+G2kv74UFHmSOlg5+i/vF3XxuR522V4u8BqO+Q=="
},
"cookie": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
}
}
},
"copy-anything": { "copy-anything": {
"version": "3.0.5", "version": "3.0.5",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
"integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
"dev": true,
"requires": { "requires": {
"is-what": "^4.1.8" "is-what": "^4.1.8"
} }
@ -12961,7 +13036,8 @@
"is-what": { "is-what": {
"version": "4.1.15", "version": "4.1.15",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.15.tgz", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.15.tgz",
"integrity": "sha512-uKua1wfy3Yt+YqsD6mTUEa2zSi3G1oPlqTflgaPJ7z63vUGN5pxFpnQfeSLMFnJDEsdvOtkp1rUWkYjB4YfhgA==" "integrity": "sha512-uKua1wfy3Yt+YqsD6mTUEa2zSi3G1oPlqTflgaPJ7z63vUGN5pxFpnQfeSLMFnJDEsdvOtkp1rUWkYjB4YfhgA==",
"dev": true
}, },
"is-wsl": { "is-wsl": {
"version": "2.2.0", "version": "2.2.0",
@ -13795,7 +13871,8 @@
"remove-accents": { "remove-accents": {
"version": "0.4.2", "version": "0.4.2",
"resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz", "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz",
"integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==" "integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==",
"dev": true
}, },
"resolve": { "resolve": {
"version": "1.22.4", "version": "1.22.4",
@ -14157,6 +14234,7 @@
"version": "1.13.1", "version": "1.13.1",
"resolved": "https://registry.npmjs.org/superjson/-/superjson-1.13.1.tgz", "resolved": "https://registry.npmjs.org/superjson/-/superjson-1.13.1.tgz",
"integrity": "sha512-AVH2eknm9DEd3qvxM4Sq+LTCkSXE2ssfh1t11MHMXyYXFQyQ1HLgVvV+guLTsaQnJU3gnaVo34TohHPulY/wLg==", "integrity": "sha512-AVH2eknm9DEd3qvxM4Sq+LTCkSXE2ssfh1t11MHMXyYXFQyQ1HLgVvV+guLTsaQnJU3gnaVo34TohHPulY/wLg==",
"dev": true,
"requires": { "requires": {
"copy-anything": "^3.0.2" "copy-anything": "^3.0.2"
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "tuya-admin-front", "name": "front-boilerplate",
"version": "0.1.0", "version": "0.0.1",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
@ -9,17 +9,11 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@sdt/sdt-ui-kit": "^0.1.17", "@sdt/sdt-ui-kit": "^0.1.20",
"@tanstack/react-query": "^4.33.0", "@tanstack/react-query": "^4.33.0",
"@tanstack/react-query-devtools": "^4.33.0",
"@types/lodash": "^4.14.197",
"@types/node": "20.5.1",
"@types/qs": "^6.9.7",
"@types/react": "18.2.20",
"@types/react-dom": "18.2.7",
"@types/react-modal": "^3.16.0",
"autoprefixer": "10.4.15", "autoprefixer": "10.4.15",
"axios": "^1.4.0", "axios": "^1.4.0",
"cookies-next": "^3.0.0",
"eslint": "8.47.0", "eslint": "8.47.0",
"eslint-config-next": "13.4.19", "eslint-config-next": "13.4.19",
"lodash": "^4.17.21", "lodash": "^4.17.21",
@ -37,6 +31,13 @@
"zustand": "^4.4.1" "zustand": "^4.4.1"
}, },
"devDependencies": { "devDependencies": {
"@tanstack/react-query-devtools": "^4.33.0",
"@types/lodash": "^4.14.197",
"@types/node": "20.5.1",
"@types/qs": "^6.9.7",
"@types/react": "18.2.20",
"@types/react-dom": "18.2.7",
"@types/react-modal": "^3.16.0",
"@typescript-eslint/eslint-plugin": "^6.4.1", "@typescript-eslint/eslint-plugin": "^6.4.1",
"@typescript-eslint/parser": "^6.4.1", "@typescript-eslint/parser": "^6.4.1",
"eslint-config-next": "13.4.19", "eslint-config-next": "13.4.19",

View File

@ -1,9 +1,5 @@
import { import { ACCESS_TOKEN_NAME, REFREASH_TOKEN_NAME } from '@/utils';
ACCESS_TOKEN_NAME, import { deleteCookie, getCookie } from 'cookies-next';
getCookie,
REFREASH_TOKEN_NAME,
removeCookie,
} from '../utils/cookies';
import { setToken } from '../utils/setToken'; import { setToken } from '../utils/setToken';
import axios, { AxiosRequestConfig, Method } from 'axios'; import axios, { AxiosRequestConfig, Method } from 'axios';
import { silentSignInApi } from './oauth'; import { silentSignInApi } from './oauth';
@ -55,6 +51,7 @@ export const fetchApi = ({
defaultInstance.interceptors.request.use( defaultInstance.interceptors.request.use(
(req: any) => { (req: any) => {
// console.log('######## req interceptors', req); // console.log('######## req interceptors', req);
// todo fix
const SDT_AT = getCookie(ACCESS_TOKEN_NAME); const SDT_AT = getCookie(ACCESS_TOKEN_NAME);
if (noToken) { if (noToken) {
@ -101,9 +98,9 @@ export const fetchApi = ({
originalRequest.headers['Authorization'] = `Bearer ${accessToken}`; originalRequest.headers['Authorization'] = `Bearer ${accessToken}`;
return fetchApi({ ...originalRequest }); return fetchApi({ ...originalRequest });
} else { } else {
removeCookie(REFREASH_TOKEN_NAME); deleteCookie(REFREASH_TOKEN_NAME);
removeCookie(ACCESS_TOKEN_NAME); deleteCookie(ACCESS_TOKEN_NAME);
return (window.location.href = `${process.env.NEXT_PUBLIC_CLOUD_CONSOLE_PATH}/login?redirect=${window.location.href}`); return (window.location.href = `/login`);
} }
}); });
} }

View File

@ -1,6 +1,7 @@
import { getCookie, REFREASH_TOKEN_NAME } from '../../utils/cookies'; import { REFREASH_TOKEN_NAME } from '@/utils';
import qs from 'qs'; import qs from 'qs';
import { fetchApi, afterAxios } from '../config'; import { fetchApi, afterAxios } from '../config';
import { getCookie } from 'cookies-next';
export interface SignInRequestType { export interface SignInRequestType {
email: string; email: string;

View File

@ -1,9 +1,15 @@
import "./globals.css"; import QueryClientProvider from '@/utils/QueryClientProvider';
import type { Metadata } from "next"; import './globals.css';
import type { Metadata } from 'next';
import StyledComponentsRegistry from '@/utils/StyledComponentProvider/StyledComponentProvider';
import Layout from '@/components/Layout';
import { ACCESS_TOKEN_NAME } from '@/utils';
import { defaultInstance } from '@/api/config';
import { cookies } from 'next/headers';
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Create Next App", title: 'Create Next App',
description: "Generated by create next app", description: 'Generated by create next app',
}; };
export default function RootLayout({ export default function RootLayout({
@ -11,9 +17,21 @@ export default function RootLayout({
}: { }: {
children: React.ReactNode; children: React.ReactNode;
}) { }) {
const accessToken = cookies().get(ACCESS_TOKEN_NAME);
if (accessToken) {
defaultInstance.defaults.headers.common.Authorization = `Bearer ${accessToken.value}`;
}
return ( return (
<html> <html>
<body>{children}</body> <body>
<QueryClientProvider>
<StyledComponentsRegistry>
<Layout>{children}</Layout>
</StyledComponentsRegistry>
</QueryClientProvider>
</body>
</html> </html>
); );
} }

View File

@ -1 +0,0 @@
export { default } from './Login';

View File

@ -1,8 +1,8 @@
"use client"; 'use client';
import { Button, TextInput } from "@sdt/sdt-ui-kit"; import { Button, TextInput } from '@sdt/sdt-ui-kit';
import Link from "next/link"; import Link from 'next/link';
import useLogin from "../hooks/useLogin"; import useLogin from '../hooks/useLogin';
import { emailRegex, passwordRegex } from "@/utils/reg"; import { emailRegex, passwordRegex } from '@/utils/reg';
interface LoginPropsType {} interface LoginPropsType {}
@ -13,38 +13,36 @@ function Login({}: LoginPropsType) {
return ( return (
<div className="flex justify-center items-center w-full h-screen bg-cover bg-center"> <div className="flex justify-center items-center w-full h-screen bg-cover bg-center">
<div className="w-[37.5rem] shadow-md border rounded-[16px] px-10 sm:px-14 lg:px-5 py-7 sm:py-9 flex flex-col justify-center"> <div className="w-[37.5rem] shadow-md border rounded-[16px] px-10 sm:px-14 lg:px-5 py-7 sm:py-9 flex flex-col justify-center">
<h1 className="font-title-32 text-center"> </h1>
<form onSubmit={handleSubmit((data) => console.log(data))}> <form onSubmit={handleSubmit((data) => console.log(data))}>
<div className="mt-5 flex flex-col"> <div className="mt-5 flex flex-col">
<TextInput <TextInput
{...register("email", { {...register('email', {
required: "이메일을 입력하세요.", required: '이메일을 입력하세요.',
pattern: { pattern: {
value: emailRegex, value: emailRegex,
message: "올바른 이메일을 입력하세요.", message: '올바른 이메일을 입력하세요.',
}, },
})} })}
error={!!formState.errors.email} error={!!formState.errors.email}
message={(formState.errors.email?.message as string) ?? ""} message={(formState.errors.email?.message as string) ?? ''}
maxLength={40} maxLength={40}
type="text" type="text"
className={`rounded-t-[6px] text-[20px] w-full`} className={`rounded-t-[6px] text-[20px] w-full`}
placeholder="이메일 주소" placeholder="이메일 주소"
/> />
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<TextInput <TextInput
{...register("password", { {...register('password', {
required: "비밀번호를 다시 입력하세요.", required: '비밀번호를 다시 입력하세요.',
pattern: { pattern: {
value: passwordRegex, value: passwordRegex,
message: message:
"8~16자 영문 대 소문자, 숫자, 특수문자를 사용하세요.", '8~16자 영문 대 소문자, 숫자, 특수문자를 사용하세요.',
}, },
})} })}
error={!!formState.errors.password?.message} error={!!formState.errors.password?.message}
message={(formState.errors.password?.message as string) ?? ""} message={(formState.errors.password?.message as string) ?? ''}
maxLength={16} maxLength={16}
type="password" type="password"
className={`rounded-b-[6px] text-[20px] w-full border-t-none`} className={`rounded-b-[6px] text-[20px] w-full border-t-none`}
@ -64,9 +62,7 @@ function Login({}: LoginPropsType) {
<div className="w-full mt-2 flex justify-center"> <div className="w-full mt-2 flex justify-center">
<span className="mr-3 text-[#9e9e9e]"> ?</span> <span className="mr-3 text-[#9e9e9e]"> ?</span>
<Link href={"/reset-password"} className="text-teal-500"> <Link href={'/reset-password'}> </Link>
</Link>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,10 +1,7 @@
"use client";
import StyledComponentsRegistry from "@/components/__common/StyledComponentProvider/StyledComponentProvider";
export default function LoginLayout({ export default function LoginLayout({
children, children,
}: { }: {
children: React.ReactNode; children: React.ReactNode;
}) { }) {
return <StyledComponentsRegistry>{children}</StyledComponentsRegistry>; return <>{children}</>;
} }

View File

@ -1,10 +1,8 @@
import React from 'react'; import React from 'react';
import Login from './Login/Login'; import Login from './components/Login';
function LoginPage() { function LoginPage() {
return ( return <Login />;
<Login />
);
} }
export default LoginPage; export default LoginPage;

View File

@ -1,4 +1,4 @@
import Image from 'next/image' import Image from 'next/image';
export default function Home() { export default function Home() {
return ( return (
@ -109,5 +109,5 @@ export default function Home() {
</a> </a>
</div> </div>
</main> </main>
) );
} }

View File

@ -1,6 +1,7 @@
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect } from 'react';
import { useRouter } from 'next/router';
import { useAlertStore } from '@/stores'; import { useAlertStore } from '@/stores';
import { usePathname } from 'next/navigation';
export function useAlert() { export function useAlert() {
const { const {
@ -10,7 +11,8 @@ export function useAlert() {
setAlertClose, setAlertClose,
alertCallback, alertCallback,
} = useAlertStore(); } = useAlertStore();
const router = useRouter(); const pathname = usePathname();
/** /**
* Alert Close Handler * Alert Close Handler
*/ */
@ -29,7 +31,7 @@ export function useAlert() {
setAlertClose(); setAlertClose();
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [router]); }, [pathname]);
return { alertOpen, alertContent, setAlertOpen, setAlertClose, onCloseAlert }; return { alertOpen, alertContent, setAlertOpen, setAlertClose, onCloseAlert };
} }

View File

@ -1,18 +1,15 @@
import Head from 'next/head'; 'use client';
import useAlert from '../Alert/hooks/useAlert'; import useAlert from '../Alert/hooks/useAlert';
import Alert from '../Alert'; import Alert from '../Alert';
import useSilentAuth from '@/hooks/useSilentAuth';
export default function Layout({ children }: { children: React.ReactElement }) { export default function Layout({ children }: { children: React.ReactNode }) {
const { alertOpen, alertContent, onCloseAlert } = useAlert(); const { alertOpen, alertContent, onCloseAlert } = useAlert();
useSilentAuth();
return ( return (
<div className="w-full overflow-hidden"> <div className="w-full overflow-hidden">
<Head>
<title>BlokWorks</title>
<meta name="description" content="BlokWorks" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div className="flex pt-14"> <div className="flex pt-14">
<main className={`w-full p-12`}>{children}</main> <main className={`w-full p-12`}>{children}</main>
</div> </div>

View File

@ -0,0 +1,46 @@
import { useAuthStore } from '@/stores';
import { ACCESS_TOKEN_NAME, REFREASH_TOKEN_NAME } from '@/utils';
import { getCookie, deleteCookie } from 'cookies-next';
import { usePathname, useRouter } from 'next/navigation';
import { useCallback, useEffect } from 'react';
function useSilentAuth() {
const router = useRouter();
// todo fix
const SDT_AT = getCookie(ACCESS_TOKEN_NAME) ?? '';
const { loggedIn, setSignIn, setSignOut } = useAuthStore();
const pathname = usePathname();
useEffect(() => {
if (SDT_AT && !loggedIn) {
setSignIn();
}
}, [SDT_AT, loggedIn, setSignIn]);
/**
* handle Logout
*/
const handleLogout = useCallback(async () => {
deleteCookie(ACCESS_TOKEN_NAME);
deleteCookie(REFREASH_TOKEN_NAME);
setSignOut();
}, [setSignOut]);
/**
* not Server redirect
*/
useEffect(() => {
if (
!loggedIn &&
!SDT_AT &&
!(pathname.includes('login') || pathname.includes('reset-password'))
) {
router.push(`/login`);
handleLogout();
}
}, [SDT_AT, handleLogout, loggedIn, pathname, router, setSignOut]);
return {};
}
export default useSilentAuth;

View File

@ -1,20 +1,11 @@
import { create } from 'zustand'; import { create } from 'zustand';
import { devtools } from 'zustand/middleware'; import { devtools } from 'zustand/middleware';
export interface ProfileType {
id: string;
sub: string;
iat: number;
exp: number;
}
/** /**
* Auth State Type * Auth State Type
*/ */
export interface AuthStateType { export interface AuthStateType {
loggedIn: boolean; loggedIn: boolean;
email: string | null;
profile: ProfileType | null;
} }
/** /**
@ -22,8 +13,7 @@ export interface AuthStateType {
*/ */
export interface AuthActionType { export interface AuthActionType {
setSignIn: (by: ProfileType) => void; setSignIn: () => void;
setEmail: (by: string) => void;
setSignOut: () => void; setSignOut: () => void;
} }
@ -33,19 +23,14 @@ export const useAuthStore = create<AuthStoreType>()(
devtools( devtools(
(set): AuthStoreType => ({ (set): AuthStoreType => ({
loggedIn: false, loggedIn: false,
email: null,
profile: null,
setSignIn: (by: ProfileType) => setSignIn: () =>
set(() => ({ set(() => ({
profile: { ...by },
loggedIn: true, loggedIn: true,
})), })),
setEmail: (by: string) => set(() => ({ email: by })),
setSignOut: () => setSignOut: () =>
set(() => ({ set(() => ({
loggedIn: false, loggedIn: false,
email: null,
})), })),
}), }),
{ name: 'auth' }, { name: 'auth' },

View File

@ -0,0 +1,18 @@
'use client';
import React from 'react';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
function Providers({ children }: React.PropsWithChildren) {
const [client] = React.useState(new QueryClient());
return (
<QueryClientProvider client={client}>
{children}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
export default Providers;

View File

@ -0,0 +1 @@
export { default } from './QueryClientProviider';

View File

@ -1,7 +1,7 @@
"use client"; 'use client';
import React, { useState } from "react"; import React, { useState } from 'react';
import { useServerInsertedHTML } from "next/navigation"; import { useServerInsertedHTML } from 'next/navigation';
import { ServerStyleSheet, StyleSheetManager } from "styled-components"; import { ServerStyleSheet, StyleSheetManager } from 'styled-components';
export default function StyledComponentsRegistry({ export default function StyledComponentsRegistry({
children, children,
@ -18,7 +18,7 @@ export default function StyledComponentsRegistry({
return styles; return styles;
}); });
if (typeof window !== "undefined") return <>{children}</>; if (typeof window !== 'undefined') return <>{children}</>;
return ( return (
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}> <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>

View File

@ -1,25 +0,0 @@
import { Cookies } from 'react-cookie';
import { CookieSetOptions } from 'universal-cookie';
const cookies = new Cookies();
export const REFREASH_TOKEN_NAME = 'SDT_RT';
export const ACCESS_TOKEN_NAME = 'SDT_AT';
export const setCookie = (
name: string,
value: string,
option: CookieSetOptions | undefined,
) => {
return cookies.set(name, value, { ...option });
};
export const getCookie = (name: string) => {
return cookies.get(name);
};
export const removeCookie = (name: string) => {
return cookies.remove(name, {
path: '/',
});
};

View File

@ -1,3 +1,2 @@
export * from './cookies';
export * from './setToken'; export * from './setToken';
export * from './reg'; export * from './reg';

View File

@ -1,5 +1,9 @@
import { SignInResponseType } from '../api/oauth'; import { SignInResponseType } from '../api/oauth';
import { ACCESS_TOKEN_NAME, REFREASH_TOKEN_NAME, setCookie } from './cookies'; import { setCookie } from 'cookies-next';
// todo fix
export const REFREASH_TOKEN_NAME = 'SDT_RT';
export const ACCESS_TOKEN_NAME = 'SDT_AT';
export function setToken( export function setToken(
loginResponse: SignInResponseType, loginResponse: SignInResponseType,