diff --git a/frontend/index.html b/frontend/index.html index a634f017..50c8ad0e 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -10,7 +10,7 @@ href="https://cdn.jsdelivr.net/npm/pretendard/dist/web/static/pretendard.css" /> - Vite + React + 세종투자연구회
diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 28fdf4ca..b6de548c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,13 +10,14 @@ "dependencies": { "axios": "^1.13.1", "immer": "^10.2.0", + "lucide-react": "^0.555.0", "pretendard": "^1.3.9", "react": "^19.1.1", "react-day-picker": "^9.11.1", "react-dom": "^19.1.1", "react-router-dom": "^7.9.1", - "recharts": "^3.4.1", "react-toastify": "^11.0.5", + "recharts": "^3.4.1", "use-immer": "^0.11.0", "uuid": "^13.0.0" }, @@ -2332,32 +2333,6 @@ } } }, - "node_modules/@reduxjs/toolkit": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.10.1.tgz", - "integrity": "sha512-/U17EXQ9Do9Yx4DlNGU6eVNfZvFJfYpUtRRdLf19PbPjdWBxNlxGZXywQZ1p1Nz8nMkWplTI7iD/23m07nolDA==", - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@standard-schema/utils": "^0.3.0", - "immer": "^10.2.0", - "redux": "^5.0.1", - "redux-thunk": "^3.1.0", - "reselect": "^5.1.0" - }, - "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", - "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-redux": { - "optional": true - } - } - }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.34", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.34.tgz", @@ -2742,18 +2717,6 @@ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", "license": "MIT" }, - "node_modules/@standard-schema/spec": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", - "license": "MIT" - }, - "node_modules/@standard-schema/utils": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", - "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", - "license": "MIT" - }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -2875,69 +2838,6 @@ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "license": "MIT" }, - "node_modules/@types/d3-array": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", - "license": "MIT" - }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", - "license": "MIT" - }, - "node_modules/@types/d3-ease": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", - "license": "MIT" - }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", - "license": "MIT", - "dependencies": { - "@types/d3-color": "*" - } - }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", - "license": "MIT" - }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", - "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", - "license": "MIT", - "dependencies": { - "@types/d3-time": "*" - } - }, - "node_modules/@types/d3-shape": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", - "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", - "license": "MIT", - "dependencies": { - "@types/d3-path": "*" - } - }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", - "license": "MIT" - }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", - "license": "MIT" - }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -2957,7 +2857,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz", "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==", "devOptional": true, - "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -2993,12 +2892,6 @@ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", "license": "MIT" }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", - "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", - "license": "MIT" - }, "node_modules/@vitejs/plugin-react": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.2.tgz", @@ -3498,24 +3391,6 @@ "node": ">=6" } }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3632,7 +3507,6 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "devOptional": true, - "devOptional": true, "license": "MIT" }, "node_modules/d3-array": { @@ -3756,127 +3630,6 @@ "node": ">=12" } }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "license": "ISC", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "license": "ISC", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "license": "ISC", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "license": "ISC", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -3971,12 +3724,6 @@ "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", "license": "MIT" }, - "node_modules/decimal.js-light": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", - "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", - "license": "MIT" - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4272,16 +4019,6 @@ "benchmarks" ] }, - "node_modules/es-toolkit": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.42.0.tgz", - "integrity": "sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] - }, "node_modules/esbuild": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", @@ -4589,12 +4326,6 @@ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "license": "MIT" - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5139,26 +4870,6 @@ "url": "https://opencollective.com/immer" } }, - "node_modules/immer": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", - "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/immer": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", - "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -5229,15 +4940,6 @@ "node": ">=12" } }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -5923,6 +5625,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.555.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.555.0.tgz", + "integrity": "sha512-D8FvHUGbxWBRQM90NZeIyhAvkFfsh3u9ekrMvJ30Z6gnpBHS6HC6ldLg7tL45hwiIz/u66eKDtdA23gwwGsAHA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -6465,29 +6176,6 @@ } } }, - "node_modules/react-redux": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", - "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", - "license": "MIT", - "dependencies": { - "@types/use-sync-external-store": "^0.0.6", - "use-sync-external-store": "^1.4.0" - }, - "peerDependencies": { - "@types/react": "^18.2.25 || ^19", - "react": "^18.0 || ^19", - "redux": "^5.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", @@ -6536,49 +6224,17 @@ "react-dom": ">=18" } }, - "node_modules/recharts": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.4.1.tgz", - "integrity": "sha512-35kYg6JoOgwq8sE4rhYkVWwa6aAIgOtT+Ob0gitnShjwUwZmhrmy7Jco/5kJNF4PnLXgt9Hwq+geEMS+WrjU1g==", + "node_modules/react-toastify": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz", + "integrity": "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==", "license": "MIT", - "workspaces": [ - "www" - ], "dependencies": { - "@reduxjs/toolkit": "1.x.x || 2.x.x", - "clsx": "^2.1.1", - "decimal.js-light": "^2.5.1", - "es-toolkit": "^1.39.3", - "eventemitter3": "^5.0.1", - "immer": "^10.1.1", - "react-redux": "8.x.x || 9.x.x", - "reselect": "5.1.1", - "tiny-invariant": "^1.3.3", - "use-sync-external-store": "^1.2.2", - "victory-vendor": "^37.0.2" - }, - "engines": { - "node": ">=18" + "clsx": "^2.1.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/redux": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", - "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" - }, - "node_modules/redux-thunk": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", - "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", - "license": "MIT", - "peerDependencies": { - "redux": "^5.0.0" + "react": "^18 || ^19", + "react-dom": "^18 || ^19" } }, "node_modules/recharts": { @@ -6626,19 +6282,6 @@ "redux": "^5.0.0" } }, - "node_modules/react-toastify": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz", - "integrity": "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==", - "license": "MIT", - "dependencies": { - "clsx": "^2.1.1" - }, - "peerDependencies": { - "react": "^18 || ^19", - "react-dom": "^18 || ^19" - } - }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -6770,12 +6413,6 @@ "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", "license": "MIT" }, - "node_modules/reselect": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", - "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", - "license": "MIT" - }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -7394,12 +7031,6 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, - "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/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -7669,35 +7300,14 @@ "punycode": "^2.1.0" } }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "node_modules/use-immer": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/use-immer/-/use-immer-0.11.0.tgz", + "integrity": "sha512-RNAqi3GqsWJ4bcCd4LMBgdzvPmTABam24DUaFiKfX9s3MSorNRz9RDZYJkllJoMHUxVLMDetwAuCDeyWNrp1yA==", "license": "MIT", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/victory-vendor": { - "version": "37.3.6", - "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", - "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", - "license": "MIT AND ISC", - "dependencies": { - "@types/d3-array": "^3.0.3", - "@types/d3-ease": "^3.0.0", - "@types/d3-interpolate": "^3.0.1", - "@types/d3-scale": "^4.0.2", - "@types/d3-shape": "^3.1.0", - "@types/d3-time": "^3.0.0", - "@types/d3-timer": "^3.0.0", - "d3-array": "^3.1.6", - "d3-ease": "^3.0.1", - "d3-interpolate": "^3.0.1", - "d3-scale": "^4.0.2", - "d3-shape": "^3.1.0", - "d3-time": "^3.0.0", - "d3-timer": "^3.0.1" + "immer": ">=8.0.0", + "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/use-sync-external-store": { @@ -7709,6 +7319,19 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/uuid": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, "node_modules/victory-vendor": { "version": "37.3.6", "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", @@ -7731,29 +7354,6 @@ "d3-timer": "^3.0.1" } }, - "node_modules/use-immer": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/use-immer/-/use-immer-0.11.0.tgz", - "integrity": "sha512-RNAqi3GqsWJ4bcCd4LMBgdzvPmTABam24DUaFiKfX9s3MSorNRz9RDZYJkllJoMHUxVLMDetwAuCDeyWNrp1yA==", - "license": "MIT", - "peerDependencies": { - "immer": ">=8.0.0", - "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/uuid": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", - "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" - } - }, "node_modules/vite": { "version": "7.1.5", "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz", diff --git a/frontend/package.json b/frontend/package.json index 5b583fac..098cdbc1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,13 +12,14 @@ "dependencies": { "axios": "^1.13.1", "immer": "^10.2.0", + "lucide-react": "^0.555.0", "pretendard": "^1.3.9", "react": "^19.1.1", "react-day-picker": "^9.11.1", "react-dom": "^19.1.1", "react-router-dom": "^7.9.1", - "recharts": "^3.4.1", "react-toastify": "^11.0.5", + "recharts": "^3.4.1", "use-immer": "^0.11.0", "uuid": "^13.0.0" }, diff --git a/frontend/src/components/VerificationModal.jsx b/frontend/src/components/VerificationModal.jsx index 3374378e..f07876a6 100644 --- a/frontend/src/components/VerificationModal.jsx +++ b/frontend/src/components/VerificationModal.jsx @@ -1,5 +1,6 @@ import { useState } from 'react'; import styles from './VerificationModal.module.css'; +import { toast } from 'react-toastify'; const VerificationModal = ({ title, onClose, onSuccess }) => { const [phoneNumber, setPhoneNumber] = useState(''); @@ -12,7 +13,7 @@ const VerificationModal = ({ title, onClose, onSuccess }) => { // 전화번호 형식에 맞지 않을 시 return const phoneRegex = /^01[0-9]{1}[0-9]{7,8}$/; if (!phoneNumber || !phoneRegex.test(phoneNumber)) { - alert('올바른 전화번호 형식을 입력해주세요. (예: 01012345678)'); + toast.error('올바른 전화번호 형식을 입력해주세요. (예: 01012345678)'); return; } @@ -20,7 +21,7 @@ const VerificationModal = ({ title, onClose, onSuccess }) => { console.log(`${phoneNumber}로 인증번호 전송 API 호출`); // 실제 api 추가 - alert('인증번호가 전송되었습니다.'); + toast.success('인증번호가 전송되었습니다.'); setIsCodeSent(true); setTimeout(() => setSendButtonDisabled(false), 3000); }; @@ -28,7 +29,7 @@ const VerificationModal = ({ title, onClose, onSuccess }) => { const handleSubmit = async (e) => { e.preventDefault(); if (!verificationCode) { - alert('인증번호를 입력해주세요.'); + toast.error('인증번호를 입력해주세요.'); return; } console.log(`${phoneNumber}와 ${verificationCode}로 인증 확인 API 호출`); @@ -37,11 +38,11 @@ const VerificationModal = ({ title, onClose, onSuccess }) => { // <<-- 실제 API 호출 로직: const result = await api.verifyCode(phoneNumber, code) -->> const mockResult = { email: 'user@example.com', message: '인증 성공' }; - alert('인증에 성공했습니다!'); + toast.success('인증에 성공했습니다!'); onSuccess(mockResult); } catch (error) { console.error('인증 실패:', error); - alert('인증번호가 올바르지 않습니다.'); + toast.error('인증번호가 올바르지 않습니다.'); } }; diff --git a/frontend/src/components/attendance/AttendanceSelectBox.css b/frontend/src/components/attendance/AttendanceSelectBox.css deleted file mode 100644 index a08c9ffb..00000000 --- a/frontend/src/components/attendance/AttendanceSelectBox.css +++ /dev/null @@ -1,54 +0,0 @@ -.attendance-box { - display: flex; - width: 80%; - height: 69px; - - align-items: center; - gap: 10px; - flex-shrink: 0; - - border-radius: 12px; - background: #2c2d2f; - justify-content: space-between; - - transition: all 0.2s; -} -.attendance-box:hover { - transition: all 0.2s; - transform: scale(1.03); /* 크기 3% 확대 */ - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); /* 살짝 그림자 추가 */ -} - -.at-left-content { - display: flex; - flex-direction: row; - align-items: center; -} - -.at-icon-circle { - padding-left: 8px; - width: 50px; - height: 50px; -} -.at_icon { - width: 100%; - height: 100%; -} - -.at-text-contanier { - text-align: center; - margin-left: 10px; -} - -.at-text, -.at-right-arrow { - color: #fff; - font-size: 20px; - font-style: normal; - font-weight: 500; - line-height: 146%; -} - -.at-right-arrow { - margin-right: 15px; -} diff --git a/frontend/src/components/attendance/AttendanceSelectBox.jsx b/frontend/src/components/attendance/AttendanceSelectBox.jsx deleted file mode 100644 index 02b882b8..00000000 --- a/frontend/src/components/attendance/AttendanceSelectBox.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import './AttendanceSelectBox.css'; - -const AttendanceSelectBox = ({ icon, text, onClick }) => { - return ( -
-
-
-
- -
-
-
{text}
-
-
-
˃
-
-
- ); -}; - -export default AttendanceSelectBox; diff --git a/frontend/src/components/attendance/ExcusedTime.jsx b/frontend/src/components/attendance/ExcusedTime.jsx new file mode 100644 index 00000000..14dcbfed --- /dev/null +++ b/frontend/src/components/attendance/ExcusedTime.jsx @@ -0,0 +1,12 @@ +import styles from './ExcusedTime.module.css'; + +const ExcusedTime = () => { + return ( +
+ 1회차 출석 인정 시간 + 18 : 00 ~ 18 : 30 +
+ ); +}; + +export default ExcusedTime; diff --git a/frontend/src/components/attendance/ExcusedTime.module.css b/frontend/src/components/attendance/ExcusedTime.module.css new file mode 100644 index 00000000..53557617 --- /dev/null +++ b/frontend/src/components/attendance/ExcusedTime.module.css @@ -0,0 +1,28 @@ +.card { + width: 335px; + height: 160px; + border: 1px solid #c9bebe; + background: #fafbfc; + border-radius: 12px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 10px; +} + +.excuse { + font-weight: 700; + font-size: 16px; + line-height: 100%; + letter-spacing: 0%; + color: #aaaaaa; +} + +.time { + font-weight: 600; + font-size: 24px; + line-height: 100%; + letter-spacing: 0%; + color: #171717; +} diff --git a/frontend/src/components/attendance/SessionManage.jsx b/frontend/src/components/attendance/SessionManage.jsx new file mode 100644 index 00000000..cee1a1e6 --- /dev/null +++ b/frontend/src/components/attendance/SessionManage.jsx @@ -0,0 +1,43 @@ +import styles from './SessionManage.module.css'; +import { ClipboardCheck } from 'lucide-react'; +import { attendanceList } from '../../utils/attendanceList'; + +const SessionManage = () => { + return ( +
+
+ + 세션 관리 +
+ + + + + + + + + + + + + + {attendanceList.map((s) => ( + + + + + + + + + ))} + +
일자출석시작시간출석가능시간회차이름
{s.date}{s.startTime}{s.available}분{s.round}회차{s.name} + +
+
+ ); +}; + +export default SessionManage; diff --git a/frontend/src/components/attendance/SessionManage.module.css b/frontend/src/components/attendance/SessionManage.module.css new file mode 100644 index 00000000..69116447 --- /dev/null +++ b/frontend/src/components/attendance/SessionManage.module.css @@ -0,0 +1,65 @@ +.card { + width: 955px; + min-height: 320px; + box-sizing: border-box; + border: 1px solid #c9bebe; + background: #fafbfc; + border-radius: 12px; + padding: 20px 40px; + display: flex; + flex-direction: column; + gap: 50px; +} + +.title { + display: flex; + align-items: center; + gap: 10px; + font-weight: 400; + font-size: 20px; + line-height: 146%; + letter-spacing: 0%; + color: #000000; +} + +.table { + width: 100%; + border-collapse: collapse; + table-layout: fixed; +} + +.table td:last-child { + text-align: right; +} + +.table thead th, +.table tbody td { + text-align: left; + padding: 8px 7px; + white-space: nowrap; + border-bottom: 0.4px solid #6a6a6a; + font-family: Inter; + font-weight: 400; + font-size: 16px; + line-height: 100%; + letter-spacing: 0%; + color: #000000; +} + +.button { + background: linear-gradient( + 92.89deg, + #d8e8ff 6.95%, + #d1d8ff 74.81%, + #dddeff 107.39% + ); + width: 70px; + height: 35px; + border-radius: 8px; + border: none; + font-weight: 400; + font-size: 16px; + line-height: 100%; + letter-spacing: 0%; + color: #000000; +} diff --git a/frontend/src/components/attendance/SessionSelectBox.jsx b/frontend/src/components/attendance/SessionSelectBox.jsx new file mode 100644 index 00000000..0d7f8301 --- /dev/null +++ b/frontend/src/components/attendance/SessionSelectBox.jsx @@ -0,0 +1,33 @@ +import styles from './SessionSelectBox.module.css'; +import { ClipboardCheck } from 'lucide-react'; + +const sessionList = [ + '증권 1팀', + '증권 2팀', + '증권 3팀', + '자신운용팀', + '금융 IT팀', + '매크로팀', + '트레이딩팀', +]; + +const SessionSelectBox = () => { + return ( +
+
+
+ +
+ ); +}; + +export default SessionSelectBox; diff --git a/frontend/src/components/attendance/SessionSelectBox.module.css b/frontend/src/components/attendance/SessionSelectBox.module.css new file mode 100644 index 00000000..bf1bf161 --- /dev/null +++ b/frontend/src/components/attendance/SessionSelectBox.module.css @@ -0,0 +1,35 @@ +.box { + border: 1px solid #c9bebe; + background: #fafbfc; + width: 600px; + height: 160px; + border-radius: 12px; + padding: 30px; + display: flex; + flex-direction: column; + gap: 30px; +} + +.title { + display: flex; + align-items: center; + gap: 5px; + font-weight: 700; + font-size: 20px; + line-height: 146%; + letter-spacing: 0%; + color: #171717; +} + +.session { + width: 280px; + height: 40px; + padding: 10px 20px; + border: 0.8px solid #afafaf; + border-radius: 8px; + font-weight: 400; + font-size: 16px; + line-height: 100%; + color: #171717; + box-sizing: border-box; +} diff --git a/frontend/src/components/login/LoginForm.jsx b/frontend/src/components/login/LoginForm.jsx index 6ac511e8..41acbfba 100644 --- a/frontend/src/components/login/LoginForm.jsx +++ b/frontend/src/components/login/LoginForm.jsx @@ -9,8 +9,9 @@ import ResetPasswordModal from './ResetPasswordModal'; import FindEmailResultModal from './FindEmailResultModal'; import { login } from '../../utils/auth'; - import { api } from './../../utils/axios.js'; +import { toast } from 'react-toastify'; + const getUserDetails = async () => { try { const res = await api.get('/api/user/details'); @@ -66,10 +67,7 @@ const LoginForm = () => { nav('/'); } catch (err) { console.dir(err); - alert( - err.data?.errorMessage || - '로그인에 실패하였습니다. 이메일과 비밀번호를 확인해주세요.' - ); + toast.error('로그인에 실패하였습니다. 이메일과 비밀번호를 확인해주세요.'); } }; diff --git a/frontend/src/components/login/ResetPasswordModal.jsx b/frontend/src/components/login/ResetPasswordModal.jsx index f3385c41..ca0de830 100644 --- a/frontend/src/components/login/ResetPasswordModal.jsx +++ b/frontend/src/components/login/ResetPasswordModal.jsx @@ -1,5 +1,6 @@ import { useState } from 'react'; import styles from '../VerificationModal.module.css'; +import { toast } from 'react-toastify'; const ResetPasswordModal = ({ onClose }) => { const [password, setPassword] = useState(''); @@ -8,15 +9,15 @@ const ResetPasswordModal = ({ onClose }) => { const handleSubmit = (e) => { e.preventDefault(); if (password !== confirmPassword) { - alert('비밀번호가 일치하지 않습니다.'); + toast.error('비밀번호가 일치하지 않습니다.'); return; } if (password.length < 8) { - alert('비밀번호는 8자 이상이어야 합니다.'); + toast.error('비밀번호는 8자 이상이어야 합니다.'); return; } console.log('비밀번호 재설정 API 호출'); - alert('비밀번호가 성공적으로 재설정되었습니다.'); + toast.success('비밀번호가 변경되었습니다.'); onClose(); // 부모에게 성공 알림 }; diff --git a/frontend/src/components/signup/SignUpForm.jsx b/frontend/src/components/signup/SignUpForm.jsx index 7067a3b0..c604b898 100644 --- a/frontend/src/components/signup/SignUpForm.jsx +++ b/frontend/src/components/signup/SignUpForm.jsx @@ -2,6 +2,7 @@ import { useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import styles from '../LoginAndSignUpForm.module.css'; import sejong_logo from '../../assets/sejong_logo.png'; +import { toast } from 'react-toastify'; import { sendVerificationNumber, @@ -84,9 +85,10 @@ const SignUpForm = () => { await sendVerificationNumber({ email: email }, abortRef.current.signal); setVerificationSent(true); - alert('인증번호가 발송되었습니다.'); - } catch (err) { - alert(err.data?.errorMessage || '전송 오류가 발생했습니다.'); + toast.success('인증번호가 발송되었습니다.'); + } catch (error) { + console.log(error); + toast.error('오류가 발생했습니다.'); } finally { setIsSending(false); } @@ -104,9 +106,10 @@ const SignUpForm = () => { ); setVerificationChecked(true); - alert('인증되었습니다.'); - } catch (err) { - alert(err.response?.data?.message || '인증에 실패했습니다.'); + toast.success('인증되었습니다.'); + } catch (error) { + console.log(error); + toast.error('인증에 실패했습니다.'); } }; @@ -127,11 +130,11 @@ const SignUpForm = () => { }, abortRef.current.signal ); - - alert('회원가입이 완료되었습니다.'); + toast.success('회원가입이 완료되었습니다.'); nav('/login'); - } catch (err) { - alert(err.data?.errorMessage || '회원가입에 실패하였습니다.'); + } catch (error) { + console.log(error); + toast.error('회원가입에 실패하였습니다.'); } }; diff --git a/frontend/src/components/stockgame/Betting.jsx b/frontend/src/components/stockgame/Betting.jsx index 2cd051dd..e9567c3a 100644 --- a/frontend/src/components/stockgame/Betting.jsx +++ b/frontend/src/components/stockgame/Betting.jsx @@ -8,6 +8,7 @@ import { getWeeklyBetHistory, } from '../../utils/bettingHistory'; import { api } from '../../utils/axios'; +import { toast } from 'react-toastify'; const Betting = ({ period }) => { const [isBetting, setIsBetting] = useState('none'); @@ -61,7 +62,7 @@ const Betting = ({ period }) => { const onClickUpBet = async () => { if (isBetting !== 'none') { - alert('이미 베팅하셨습니다.'); + toast.error('이미 베팅하셨습니다.'); } else if (confirm('상승에 베팅하시겠습니까?')) { try { const res = await api.post('/api/user-bets', { @@ -71,15 +72,15 @@ const Betting = ({ period }) => { isFree: true, }); await update(); - alert('베팅이 완료되었습니다.'); + toast.success('베팅이 완료되었습니다.'); return res; } catch (error) { // 409 처리 if (error.status === 409) { - alert('베팅 가능 시간이 아닙니다.'); + toast.error('베팅 가능 시간이 아닙니다.'); return; } - alert('오류가 발생했습니다. 다시 시도해주세요.'); + toast.error('오류가 발생했습니다. 다시 시도해주세요.'); return null; } } @@ -87,7 +88,7 @@ const Betting = ({ period }) => { const onClickDownBet = async () => { if (isBetting !== 'none') { - alert('이미 베팅하셨습니다.'); + toast.error('이미 베팅하셨습니다.'); } else if (confirm('하락에 베팅하시겠습니까?')) { try { const res = await api.post('/api/user-bets', { @@ -97,15 +98,15 @@ const Betting = ({ period }) => { isFree: true, }); await update(); - alert('베팅이 완료되었습니다.'); + toast.success('베팅이 완료되었습니다.'); return res; } catch (error) { // 409 처리 if (error.status === 409) { - alert('베팅 가능 시간이 아닙니다.'); + toast.error('베팅 가능 시간이 아닙니다.'); return; } - alert('오류가 발생했습니다. 다시 시도해주세요.'); + toast.error('오류가 발생했습니다. 다시 시도해주세요.'); return null; } } @@ -116,9 +117,9 @@ const Betting = ({ period }) => { try { await api.delete(`/api/user-bets/${userBets.userBetId}`); await update(); - alert('베팅이 취소되었습니다.'); - } catch (error) { - alert(error.message); + toast.success('베팅이 취소되었습니다.'); + } catch { + toast.error('오류가 발생했습니다. 다시 시도해주세요.'); } } }; diff --git a/frontend/src/pages/Attendance.css b/frontend/src/pages/Attendance.css deleted file mode 100644 index bac31759..00000000 --- a/frontend/src/pages/Attendance.css +++ /dev/null @@ -1,18 +0,0 @@ -.attendance-text { - color: #fff; - font-family: Pretendard; - font-size: 36px; - font-style: normal; - font-weight: 600; - line-height: 100%; - letter-spacing: 1.44px; - margin-top: 124px; -} - -.attendance-list { - margin-top: 72px; - - display: flex; - flex-direction: column; - gap: 30px; -} diff --git a/frontend/src/pages/Attendance.jsx b/frontend/src/pages/Attendance.jsx index 2a629772..7afa35d1 100644 --- a/frontend/src/pages/Attendance.jsx +++ b/frontend/src/pages/Attendance.jsx @@ -1,37 +1,22 @@ -import { useNavigate } from 'react-router-dom'; -import './Attendance.css'; -import icon1 from '../assets/at_icon_1.png'; -import icon2 from '../assets/at_icon_2.png'; -import icon3 from '../assets/at_icon_3.png'; -import AttendanceSelectBox from '../components/attendance/AttendanceSelectBox'; +import styles from './Attendance.module.css'; +import SessionSelectBox from '../components/attendance/SessionSelectBox'; +import ExcusedTime from '../components/attendance/ExcusedTime'; +import SessionManage from '../components/attendance/SessionManage'; -const attendanceSelectData = [ - // { icon: icon1, text: '전체 출석', path: '/attendance-all' }, - // { icon: icon2, text: '자산 운용 출석', path: '/attendance-asset' }, - // { icon: icon3, text: '금융 IT 출석', path: '/attendance-financeit' }, -]; +import { useAuthGuard } from '../hooks/useAuthGuard'; const Attendance = () => { - const nav = useNavigate(); + useAuthGuard(); return ( - <> -
-
출석하기
-
- {attendanceSelectData.map((item, idx) => { - return ( - nav(item.path)} - /> - ); - })} -
+
+

출석하기

+
+ +
- + +
); }; diff --git a/frontend/src/pages/Attendance.module.css b/frontend/src/pages/Attendance.module.css new file mode 100644 index 00000000..52e21ee5 --- /dev/null +++ b/frontend/src/pages/Attendance.module.css @@ -0,0 +1,23 @@ +.container { + display: flex; + flex-direction: column; + padding: 80px; + gap: 20px; + justify-content: center; + align-items: flex-start; +} + +.title { + font-weight: 600; + font-size: 36px; + line-height: 100%; + letter-spacing: 0%; + color: #171717; +} + +.attendanceSection { + margin-top: 25px; + display: flex; + gap: 20px; + justify-content: center; +} diff --git a/frontend/src/utils/attendanceList.js b/frontend/src/utils/attendanceList.js new file mode 100644 index 00000000..80a42bb4 --- /dev/null +++ b/frontend/src/utils/attendanceList.js @@ -0,0 +1,37 @@ +export const attendanceList = [ + { + date: '25-09-01', + startTime: '18:00:00', + available: 30, + round: 1, + name: '김성원', + }, + { + date: '25-09-08', + startTime: '18:00:00', + available: 10, + round: 2, + name: '김성원', + }, + { + date: '25-09-15', + startTime: '18:00:00', + available: 20, + round: 3, + name: '김성원', + }, + { + date: '25-09-22', + startTime: '18:00:00', + available: 30, + round: 4, + name: '김성원', + }, + { + date: '25-09-29', + startTime: '18:00:00', + available: 30, + round: 5, + name: '김성원', + }, +]; diff --git a/frontend/src/utils/bettingHistory.js b/frontend/src/utils/bettingHistory.js index 38bd8f23..7c88d420 100644 --- a/frontend/src/utils/bettingHistory.js +++ b/frontend/src/utils/bettingHistory.js @@ -1,4 +1,5 @@ import { api } from '../utils/axios.js'; +import { toast } from 'react-toastify'; const betHistory = async () => { try { @@ -6,8 +7,8 @@ const betHistory = async () => { // 백엔드에서 최신순으로 정렬된 데이터 반환 const filterdRes = res.data.filter((r) => r.betStatus !== 'DELETED'); return filterdRes; - } catch (error) { - console.log(error.message); + } catch { + toast.error('오류가 발생했습니다. 다시 시도해주세요.'); return null; } }; diff --git a/frontend/src/utils/bettingInfo.js b/frontend/src/utils/bettingInfo.js index 42e43099..616da207 100644 --- a/frontend/src/utils/bettingInfo.js +++ b/frontend/src/utils/bettingInfo.js @@ -1,11 +1,12 @@ import { api } from '../utils/axios.js'; +import { toast } from 'react-toastify'; export const dailyBet = async () => { try { const res = await api.get('/api/bet-rounds/DAILY'); return res.data; - } catch (error) { - console.log(error.message); + } catch { + toast.error('오류가 발생했습니다. 다시 시도해주세요.'); return null; } }; @@ -14,8 +15,8 @@ export const weeklyBet = async () => { try { const res = await api.get('/api/bet-rounds/WEEKLY'); return res.data; - } catch (error) { - console.log(error.message); + } catch { + toast.error('오류가 발생했습니다. 다시 시도해주세요.'); return null; } };