diff --git a/.eslintrc.json b/.eslintrc.json index bfaedaa..530db29 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -31,6 +31,7 @@ "@typescript-eslint/camelcase": "off", "no-console": "warn", "react/require-default-props": "off", - "import/prefer-default-export": "off" + "import/prefer-default-export": "off", + "react/jsx-props-no-spreading": "off" } } diff --git a/next.config.mjs b/next.config.mjs index 4678774..a79ebe4 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,15 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + reactStrictMode: false, + swcMinify: false, + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 'files.sulmoon.io', + }, + ], + }, +}; export default nextConfig; diff --git a/package-lock.json b/package-lock.json index 1e5c13b..1392ad3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,21 +9,33 @@ "version": "0.1.0", "dependencies": { "@fingerprintjs/fingerprintjs-pro-react": "^2.6.3", + "@hello-pangea/dnd": "^16.6.0", "@next/third-parties": "^14.2.5", + "@simbathesailor/use-what-changed": "^2.0.0", "@tanstack/react-query": "^5.50.1", "@tanstack/react-query-devtools": "^5.50.1", + "chart.js": "^4.4.4", + "chartjs-plugin-datalabels": "^2.2.0", "cookies-next": "^4.2.1", + "immer": "^10.1.1", "ky": "^1.5.0", + "moment": "^2.30.1", + "moment-timezone": "^0.5.45", "next": "14.2.4", "react": "^18", + "react-chartjs-2": "^5.2.0", + "react-datetime": "^3.2.0", "react-dom": "^18", "react-icons": "^5.2.1", - "react-toastify": "^10.0.5" + "react-toastify": "^10.0.5", + "uuid": "^10.0.0", + "zustand": "^4.5.5" }, "devDependencies": { "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^7.15.0", "@typescript-eslint/parser": "^7.15.0", "eslint": "^8.57.0", @@ -56,6 +68,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@babel/runtime": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -113,9 +137,9 @@ } }, "node_modules/@fingerprintjs/fingerprintjs-pro": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.10.1.tgz", - "integrity": "sha512-4GJ4gfxIEmyRO59TAHqsizBGLh4T5mzzbm+R7yx4YIqrGp7/mnlI4t7IpylnLBqLiPhaVThRFz4SEA08zTDfNA==", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.11.1.tgz", + "integrity": "sha512-qksDl/+N4JI3Vaj511RDGuOx/LEMHmFfhwSs4oGxyodsDhZ8PVz/dbXvayufw5JJLtIsFBhGrnoMMarDI5zT1w==", "dependencies": { "tslib": "^2.4.1" } @@ -131,12 +155,84 @@ } }, "node_modules/@fingerprintjs/fingerprintjs-pro-spa": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-spa/-/fingerprintjs-pro-spa-1.3.1.tgz", - "integrity": "sha512-1k+85IYh1bBDJY/syHzBmTzKKaPGQkpq8GO9+vf7MHdqlmIiLAcutaHMUXey9DxylKm93qCHRY/1fCOOQ/LiTA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-spa/-/fingerprintjs-pro-spa-1.3.2.tgz", + "integrity": "sha512-s1YGsx1XQLmjU+av4UrUHNxyzwPHyZRB0GXJQFOJK8ZHCYc2SNukxnJmZA++bNBa8twU3wW+QgSJhA4Prjnd0g==", "dependencies": { - "@fingerprintjs/fingerprintjs-pro": "^3.9.2", - "tslib": "^2.6.2" + "@fingerprintjs/fingerprintjs-pro": "^3.11.0", + "tslib": "^2.7.0" + } + }, + "node_modules/@hello-pangea/dnd": { + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/@hello-pangea/dnd/-/dnd-16.6.0.tgz", + "integrity": "sha512-vfZ4GydqbtUPXSLfAvKvXQ6xwRzIjUSjVU0Sx+70VOhc2xx6CdmJXJ8YhH70RpbTUGjxctslQTHul9sIOxCfFQ==", + "dependencies": { + "@babel/runtime": "^7.24.1", + "css-box-model": "^1.2.1", + "memoize-one": "^6.0.0", + "raf-schd": "^4.0.3", + "react-redux": "^8.1.3", + "redux": "^4.2.1", + "use-memo-one": "^1.1.3" + }, + "peerDependencies": { + "react": "^16.8.5 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@hello-pangea/dnd/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/@hello-pangea/dnd/node_modules/react-redux": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz", + "integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^16.8 || ^17.0 || ^18.0", + "@types/react-dom": "^16.8 || ^17.0 || ^18.0", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0", + "react-native": ">=0.59", + "redux": "^4 || ^5.0.0-beta.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/@hello-pangea/dnd/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.9.2" } }, "node_modules/@humanwhocodes/config-array": { @@ -266,6 +362,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==", + "license": "MIT" + }, "node_modules/@next/env": { "version": "14.2.4", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.4.tgz", @@ -490,6 +592,14 @@ "integrity": "sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==", "dev": true }, + "node_modules/@simbathesailor/use-what-changed": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@simbathesailor/use-what-changed/-/use-what-changed-2.0.0.tgz", + "integrity": "sha512-ulBNrPSvfho9UN6zS2fii3AsdEcp2fMaKeqUZZeCNPaZbB6aXyTUhpEN9atjMAbu/eyK3AY8L4SYJUG62Ekocw==", + "peerDependencies": { + "react": ">=16" + } + }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -558,6 +668,16 @@ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", + "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -576,14 +696,12 @@ "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "dev": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -593,11 +711,23 @@ "version": "18.3.0", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, + "devOptional": true, "dependencies": { "@types/react": "*" } }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.15.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.15.0.tgz", @@ -1259,6 +1389,27 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chart.js": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.4.tgz", + "integrity": "sha512-emICKGBABnxhMjUjlYRR12PmOXhJ2eJjEHL2/dZlWjxRAZT1D8xplLFq5M0tMQK8ja+wBS/tuVEJB5C6r7VxJA==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, + "node_modules/chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "license": "MIT", + "peerDependencies": { + "chart.js": ">=3.0.0" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -1465,6 +1616,15 @@ "node": ">= 8" } }, + "node_modules/css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", + "license": "MIT", + "dependencies": { + "tiny-invariant": "^1.0.6" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -1480,8 +1640,7 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -3039,6 +3198,15 @@ "node": ">= 0.4" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", @@ -3072,6 +3240,15 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3650,9 +3827,9 @@ } }, "node_modules/ky": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/ky/-/ky-1.5.0.tgz", - "integrity": "sha512-bkQo+UqryW6Zmo/DsixYZE4Z9t2mzvNMhceyIhuMuInb3knm5Q+GNGMKveydJAj+Z6piN1SwI6eR/V0G+Z0BtA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/ky/-/ky-1.7.2.tgz", + "integrity": "sha512-OzIvbHKKDpi60TnF9t7UUVAF1B4mcqc02z5PIvrm08Wyb+yOcz63GRvEuVxNT18a9E1SrNouhB4W2NNLeD7Ykg==", "engines": { "node": ">=18" }, @@ -4032,6 +4209,12 @@ "node": "14 || >=16.14" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -4102,6 +4285,25 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.45", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz", + "integrity": "sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4258,7 +4460,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4793,7 +4994,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -4829,6 +5029,12 @@ } ] }, + "node_modules/raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==", + "license": "MIT" + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -4840,6 +5046,28 @@ "node": ">=0.10.0" } }, + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "license": "MIT", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-datetime": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-datetime/-/react-datetime-3.2.0.tgz", + "integrity": "sha512-w5XdeNIGzBht9CadaZIJhKUhEcDTgH0XokKxGPCxeeJRYL7B3HIKA8CM6Q0xej2JFJt0n5d+zi3maMwaY3262A==", + "dependencies": { + "prop-types": "^15.5.7" + }, + "peerDependencies": { + "moment": "^2.16.0", + "react": "^16.5.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -4863,8 +5091,7 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-toastify": { "version": "10.0.5", @@ -4920,6 +5147,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -5689,6 +5922,12 @@ "resolved": "https://registry.npmjs.org/third-party-capital/-/third-party-capital-1.0.20.tgz", "integrity": "sha512-oB7yIimd8SuGptespDAZnNkzIz+NWaJCu2RMsbs4Wmp9zSDUM8Nhi3s2OOcqYuv3mN4hitXc8DVx+LyUmbUDiA==" }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5732,9 +5971,9 @@ } }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" }, "node_modules/type-check": { "version": "0.4.0", @@ -5876,12 +6115,41 @@ "punycode": "^2.1.0" } }, + "node_modules/use-memo-one": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", + "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6108,6 +6376,33 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.5.tgz", + "integrity": "sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==", + "dependencies": { + "use-sync-external-store": "1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index 8a8335e..1aab4ee 100644 --- a/package.json +++ b/package.json @@ -11,21 +11,33 @@ }, "dependencies": { "@fingerprintjs/fingerprintjs-pro-react": "^2.6.3", + "@hello-pangea/dnd": "^16.6.0", "@next/third-parties": "^14.2.5", + "@simbathesailor/use-what-changed": "^2.0.0", "@tanstack/react-query": "^5.50.1", "@tanstack/react-query-devtools": "^5.50.1", + "chart.js": "^4.4.4", + "chartjs-plugin-datalabels": "^2.2.0", "cookies-next": "^4.2.1", + "immer": "^10.1.1", "ky": "^1.5.0", + "moment": "^2.30.1", + "moment-timezone": "^0.5.45", "next": "14.2.4", "react": "^18", + "react-chartjs-2": "^5.2.0", + "react-datetime": "^3.2.0", "react-dom": "^18", "react-icons": "^5.2.1", - "react-toastify": "^10.0.5" + "react-toastify": "^10.0.5", + "uuid": "^10.0.0", + "zustand": "^4.5.5" }, "devDependencies": { "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^7.15.0", "@typescript-eslint/parser": "^7.15.0", "eslint": "^8.57.0", diff --git a/public/assets/default-thumbnail.webp b/public/assets/default-thumbnail.webp new file mode 100644 index 0000000..b34b714 Binary files /dev/null and b/public/assets/default-thumbnail.webp differ diff --git a/public/assets/default-user-icon.png b/public/assets/default-user-icon.png new file mode 100644 index 0000000..4e788d4 Binary files /dev/null and b/public/assets/default-user-icon.png differ diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx index f0243b0..4ad7508 100644 --- a/src/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -5,17 +5,17 @@ import Button from '@/components/social-login/Button'; const providers = [ { - href: `${process.env.NEXT_PUBLIC_API_URL}/oauth2/authorization/google`, + href: `${process.env.NEXT_PUBLIC_API_URL}/api/v1/login/oauth/google?redirect_path=/`, name: '구글', provider: 'google', }, + // { + // href: `${process.env.NEXT_PUBLIC_API_URL}/api/v1/login/oauth/naver?redirect_path=/`, + // name: '네이버', + // provider: 'naver', + // }, { - href: `${process.env.NEXT_PUBLIC_API_URL}/oauth2/authorization/naver`, - name: '네이버', - provider: 'naver', - }, - { - href: `${process.env.NEXT_PUBLIC_API_URL}/oauth2/authorization/kakao`, + href: `${process.env.NEXT_PUBLIC_API_URL}/api/v1/login/oauth/kakao?redirect_path=/`, name: '카카오', provider: 'kakao', }, diff --git a/src/app/(main)/mypage/page.tsx b/src/app/(main)/mypage/page.tsx new file mode 100644 index 0000000..4ea3328 --- /dev/null +++ b/src/app/(main)/mypage/page.tsx @@ -0,0 +1,118 @@ +'use client'; + +import { useState } from 'react'; +import type { MySurveys, SurveyStatus, MySurvey } from '@/services/mypage/types'; +import { useMySurveys } from '@/services/mypage/index'; +import { StatusForFilter, SortType } from '@/services/mypage/types'; +import { useAuth } from '@/hooks/useAuth'; +import { dateReaderForMyPage, yymmdd } from '@/utils/dates'; +import Error from '@/components/ui/error/Error'; +import Loading from '@/components/ui/loading/Loading'; +import Link from 'next/link'; +import Header from '@/components/mypage/Header'; +import Table from '@/components/mypage/Table'; +import Field from '@/components/mypage/Field'; +import Filter from '@/components/mypage/Filter'; // 필터 컴포넌트 임포트 +import Image from 'next/image'; + +type MyPageSurveyInfo = { + id: string; + title: string; + thumbnail: string | null; + updatedAt: string; + status: string; + responseCount: number; +}; + +const createdMapper = (arg: MyPageSurveyInfo) => { + return ( + <> + + + + + {arg.title} + + + + {arg.status} + {arg.updatedAt} + {arg.responseCount}건 + + ); +}; + +function translateSurveyStatus(finishedAt: string, status: SurveyStatus): string { + switch (status) { + case 'NOT_STARTED': + return '제작 중'; + case 'IN_PROGRESS': + return finishedAt !== null ? dateReaderForMyPage(finishedAt) : '응답 받는 중'; + case 'IN_MODIFICATION': + return '수정 중'; + case 'CLOSED': + return '마감'; + default: + return ''; + } +} + +function toMyPageSurveyInfos(mySurveys: MySurveys): MyPageSurveyInfo[] { + return mySurveys.surveys.map((survey: MySurvey) => ({ + id: survey.id, + title: survey.title, + thumbnail: survey.thumbnail, + updatedAt: yymmdd(survey.updatedAt), + status: translateSurveyStatus(survey.finishedAt, survey.status), + responseCount: survey.responseCount, + })); +} + +export default function Page() { + const { user } = useAuth(); + + // 필터와 정렬 상태 관리 + const [statusForFilter, setStatusForFilter] = useState(null); + const [sortType, setSortType] = useState('LAST_MODIFIED'); + + const { data, isLoading, isError, refetch } = useMySurveys(statusForFilter, sortType); + + const mySurveyInfos = data ? toMyPageSurveyInfos(data) : []; + + if (isLoading) return ; + if (isError) + return ( + + ); + + return ( + <> +
+ + + {/* Filter 컴포넌트 사용 */} + + + gridTemplateColumns="minmax(245px, 1fr) 120px 140px 70px" + columnNames={['제목', '상태', '수정일', '응답 수']} + data={mySurveyInfos} + dataMapper={createdMapper} + emptyMessage="제작한 설문이 없습니다." + /> + + + ); +} diff --git a/src/app/(main)/workbench/[surveyId]/page.tsx b/src/app/(main)/workbench/[surveyId]/page.tsx deleted file mode 100644 index 41fafb7..0000000 --- a/src/app/(main)/workbench/[surveyId]/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import { Nav } from '@/components/workbench/nav/Nav'; -import { BasicInfo } from '@/components/workbench/basic-info/BasicInfo'; -import { useWorkbenchSurvey } from '@/services/workbench'; - -export default function Page({ params }: { params: { surveyId: string } }) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { surveyId } = params; - - const [activeNav, setActiveNav] = useState(0); - const { data } = useWorkbenchSurvey(surveyId); - - return ( - <> -