From 2944a9836a995b31c06a1d487d33bcced6bc21df Mon Sep 17 00:00:00 2001 From: = Date: Wed, 27 Nov 2024 19:49:53 +0900 Subject: [PATCH 1/5] =?UTF-8?q?design:=20=EA=B2=BD=EB=A0=A5=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=EB=A7=81=20=EB=B0=94=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 444 +++++++++++++++++- package.json | 3 + src/api/saramin/route.ts | 4 +- .../recruit/category/Experience.tsx | 75 +-- src/components/recruit/filters.tsx | 1 + src/components/recruit/joblist.tsx | 19 +- .../resume/form/careerResumeForm.tsx | 188 +++----- 7 files changed, 565 insertions(+), 169 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f7bbd2..7bc6e9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,11 @@ "name": "jobseeker_project", "version": "0.1.0", "dependencies": { + "@emotion/react": "^11.13.5", + "@emotion/styled": "^11.13.5", "@heroicons/react": "^2.1.5", "@hookform/resolvers": "^3.9.0", + "@mui/material": "^6.1.8", "@prisma/client": "^5.16.1", "@react-spring/web": "^9.7.5", "@sentry/nextjs": "^8.13.0", @@ -1831,8 +1834,9 @@ "license": "MIT" }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "license": "MIT", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1942,6 +1946,152 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.5.tgz", + "integrity": "sha512-Z3xbtJ+UcK76eWkagZ1onvn/wAVb1GOMuR15s30Fm2wrMgC7jzpnO2JZXr4eujTTqoQFUrZIw/rT0c6Zzjca1g==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, + "node_modules/@emotion/react": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.5.tgz", + "integrity": "sha512-6zeCUxUH+EPF1s+YF/2hPVODeV/7V07YU5x+2tfuRL8MdW6rv5vb2+CBEGTGwBdux0OIERcOS+RzxeK80k2DsQ==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + }, + "node_modules/@emotion/styled": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.5.tgz", + "integrity": "sha512-gnOQ+nGLPvDXgIx119JqGalys64lhMdnNQA9TMxhDA4K0Hq5+++OE20Zs5GxiCV9r814xQ2K5WmtofSpHVW6BQ==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "dev": true, @@ -2686,6 +2836,213 @@ "events": "^3.3.0" } }, + "node_modules/@mui/core-downloads-tracker": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.8.tgz", + "integrity": "sha512-TGAvzwUg9hybDacwfIGFjI2bXYXrIqky+vMfaeay8rvT56/PNAlvIDUJ54kpT5KRc9AWAihOvtDI7/LJOThOmQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/material": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.8.tgz", + "integrity": "sha512-QZdQFnXct+7NXIzHgT3qt+sQiO7HYGZU2vymP9Xl9tUMXEOA/S1mZMMb7+WGZrk5TzNlU/kP/85K0da5V1jXoQ==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/core-downloads-tracker": "^6.1.8", + "@mui/system": "^6.1.8", + "@mui/types": "^7.2.19", + "@mui/utils": "^6.1.8", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.11", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^18.3.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^6.1.8", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, + "node_modules/@mui/private-theming": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.8.tgz", + "integrity": "sha512-TuKl7msynCNCVvhX3c0ef1sF0Qb3VHcPs8XOGB/8bdOGBr/ynmIG1yTMjZeiFQXk8yN9fzK/FDEKMFxILNn3wg==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/utils": "^6.1.8", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.8.tgz", + "integrity": "sha512-ZvEoT0U2nPLSLI+B4by4cVjaZnPT2f20f4JUPkyHdwLv65ZzuoHiTlwyhqX1Ch63p8bcJzKTHQVGisEoMK6PGA==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@emotion/cache": "^11.13.1", + "@emotion/serialize": "^1.3.2", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.8.tgz", + "integrity": "sha512-i1kLfQoWxzFpXTBQIuPoA3xKnAnP3en4I2T8xIolovSolGQX5k8vGjw1JaydQS40td++cFsgCdEU458HDNTGUA==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/private-theming": "^6.1.8", + "@mui/styled-engine": "^6.1.8", + "@mui/types": "^7.2.19", + "@mui/utils": "^6.1.8", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.19", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz", + "integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.8.tgz", + "integrity": "sha512-O2DWb1kz8hiANVcR7Z4gOB3SvPPsSQGUmStpyBDzde6dJIfBzgV9PbEQOBZd3EBsd1pB+Uv1z5LAJAbymmawrA==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/types": "^7.2.19", + "@types/prop-types": "^15.7.13", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, "node_modules/@next/env": { "version": "14.2.15", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.15.tgz", @@ -3484,6 +3841,15 @@ "node": ">=8.9.0" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@prisma/client": { "version": "5.16.2", "dev": true, @@ -6030,7 +6396,6 @@ }, "node_modules/@types/parse-json": { "version": "4.0.2", - "dev": true, "license": "MIT" }, "node_modules/@types/pg": { @@ -6054,8 +6419,9 @@ } }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "license": "MIT" + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" }, "node_modules/@types/qs": { "version": "6.9.15", @@ -6113,6 +6479,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/resolve": { "version": "1.20.6", "dev": true, @@ -7541,6 +7915,20 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.11", "license": "MIT", @@ -8399,6 +8787,14 @@ "node": ">=0.8" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "license": "MIT", @@ -8596,7 +8992,6 @@ }, "node_modules/cosmiconfig": { "version": "7.1.0", - "dev": true, "license": "MIT", "dependencies": { "@types/parse-json": "^4.0.0", @@ -8611,7 +9006,6 @@ }, "node_modules/cosmiconfig/node_modules/yaml": { "version": "1.10.2", - "dev": true, "license": "ISC", "engines": { "node": ">= 6" @@ -9179,6 +9573,15 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dom-serializer": { "version": "1.4.1", "dev": true, @@ -9648,7 +10051,6 @@ }, "node_modules/escape-string-regexp": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10831,6 +11233,11 @@ "node": ">=8" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "5.0.0", "dev": true, @@ -11615,7 +12022,6 @@ "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==", - "dev": true, "dependencies": { "react-is": "^16.7.0" } @@ -19157,6 +19563,21 @@ "react": ">= 0.14.0" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "license": "MIT", @@ -20684,6 +21105,11 @@ } } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/sucrase": { "version": "3.35.0", "license": "MIT", diff --git a/package.json b/package.json index dcfe343..9bc1edd 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,11 @@ "test:coverage": "react-scripts test --watchAll=false --coverage" }, "dependencies": { + "@emotion/react": "^11.13.5", + "@emotion/styled": "^11.13.5", "@heroicons/react": "^2.1.5", "@hookform/resolvers": "^3.9.0", + "@mui/material": "^6.1.8", "@prisma/client": "^5.16.1", "@react-spring/web": "^9.7.5", "@sentry/nextjs": "^8.13.0", diff --git a/src/api/saramin/route.ts b/src/api/saramin/route.ts index 1874329..bd6deb7 100644 --- a/src/api/saramin/route.ts +++ b/src/api/saramin/route.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { Job } from '@/components/recruit/job'; -const baseUrl = process.env.NEXT_PUBLIC_API_URL?.replace(/\/$/, ''); +const baseUrl = process.env.NEXT_PUBLIC_API_URL; interface FetchJobsParams { page: number; @@ -31,7 +31,7 @@ export async function fetchJobs( ): Promise<{ jobs: Job[]; totalPages: number }> { try { console.log('Fetching jobs with params:', params); - const response = await axios.get(`${baseUrl}/job-info`, { params }); + const response = await axios.get(`${baseUrl}job-info`, { params }); // console.log('API response:', response.data); return { jobs: response.data.data.content, diff --git a/src/components/recruit/category/Experience.tsx b/src/components/recruit/category/Experience.tsx index e8c064c..674430a 100644 --- a/src/components/recruit/category/Experience.tsx +++ b/src/components/recruit/category/Experience.tsx @@ -1,5 +1,5 @@ +import Slider from '@mui/material/Slider'; import React, { useState, useEffect } from 'react'; -import ReactSlider from 'react-slider'; interface ExperienceFilterProps { selectedExperienceMin: number; @@ -12,17 +12,19 @@ const Experience: React.FC = ({ selectedExperienceMax, onExperienceChange, }) => { - const [sliderValues, setSliderValues] = useState<[number, number]>([0, 10]); + const [value, setValue] = useState([0, 10]); useEffect(() => { const min = isNaN(selectedExperienceMin) ? 0 : selectedExperienceMin; const max = isNaN(selectedExperienceMax) ? 10 : selectedExperienceMax; - setSliderValues([min, max]); + setValue([min, max]); }, [selectedExperienceMin, selectedExperienceMax]); - const handleSliderChange = (value: [number, number]) => { - setSliderValues(value); - onExperienceChange(value[0], value[1]); + const handleChange = (_event: Event, newValue: number | number[]) => { + setValue(newValue as number[]); + if (Array.isArray(newValue)) { + onExperienceChange(newValue[0], newValue[1]); + } }; const formatExperience = (years: number) => { @@ -34,41 +36,40 @@ const Experience: React.FC = ({ return (
-

경력

-
- {sliderValues[0] === sliderValues[1] - ? formatExperience(sliderValues[0]) - : `${formatExperience(sliderValues[0])} ~ ${formatExperience(sliderValues[1])}`} +
+ {value[0] === value[1] + ? formatExperience(value[0]) + : `${formatExperience(value[0])} ~ ${formatExperience(value[1])}`}
-
- +
diff --git a/src/components/recruit/filters.tsx b/src/components/recruit/filters.tsx index eb0a0c2..5e55647 100644 --- a/src/components/recruit/filters.tsx +++ b/src/components/recruit/filters.tsx @@ -113,6 +113,7 @@ const Filters: React.FC = ({ filters, setFilters, applyFilters }) />
*/}
+

경력

void; + isLoading: boolean; } -const JobList: React.FC = ({ jobs, currentPage, totalPages, onPageChange }) => { +const JobList: React.FC = ({ + jobs, + currentPage, + totalPages, + onPageChange, + isLoading, +}) => { const [sortOrder, setSortOrder] = useState<'latest' | 'oldest' | null>(null); const [bookmarks, setBookmarks] = useState>(new Set()); @@ -77,6 +84,14 @@ const JobList: React.FC = ({ jobs, currentPage, totalPages, onPage return 0; }); + if (isLoading) { + return ( +
+ +
+ ); + } + return (
diff --git a/src/components/resume/form/careerResumeForm.tsx b/src/components/resume/form/careerResumeForm.tsx index b94aa00..230cea2 100644 --- a/src/components/resume/form/careerResumeForm.tsx +++ b/src/components/resume/form/careerResumeForm.tsx @@ -1,132 +1,82 @@ -/* eslint-disable */ +import Slider from '@mui/material/Slider'; +import React, { useState, useEffect } from 'react'; -import * as React from 'react'; -import { useAtom } from 'jotai'; -import { careerResumeAtom, errorsAtom } from './ResumeAtoms'; -import { ICareerResume } from '@/types/resume'; +interface ExperienceFilterProps { + selectedExperienceMin: number; + selectedExperienceMax: number; + onExperienceChange: (min: number, max: number) => void; +} -const CareerResumeForm: React.FC = () => { - const [careerList, setCareerList] = useAtom(careerResumeAtom); - const [careerErrors, setCareerErrors] = useAtom(errorsAtom); +const Experience: React.FC = ({ + selectedExperienceMin, + selectedExperienceMax, + onExperienceChange, +}) => { + const [value, setValue] = useState([0, 10]); - // 입력 필드 변경 시 호출되는 함수 - const handleChange = ( - index: number, - event: React.ChangeEvent, - ) => { - const { name, value } = event.target; - const updatedList = [...careerList]; - updatedList[index] = { ...updatedList[index], [name]: value }; + useEffect(() => { + const min = isNaN(selectedExperienceMin) ? 0 : selectedExperienceMin; + const max = isNaN(selectedExperienceMax) ? 10 : selectedExperienceMax; + setValue([min, max]); + }, [selectedExperienceMin, selectedExperienceMax]); - setCareerList(updatedList); - - // 에러 메시지 초기화 - setCareerErrors((prevErrors) => ({ - ...prevErrors, - careerResume: { - ...prevErrors.careerResume, - [index]: { - ...prevErrors.careerResume?.[index], - [name]: '', - }, - }, - })); - }; - - const handleAdd = () => { - setCareerList([ - ...careerList, - { - company_name: '', - department: '', - status: 'WORKING', - start_date: '', - end_date: '', - }, - ]); + const handleChange = (_event: Event, newValue: number | number[]) => { + setValue(newValue as number[]); + if (Array.isArray(newValue)) { + onExperienceChange(newValue[0], newValue[1]); + } }; - const handleDelete = (index: number) => { - setCareerList(careerList.filter((_, i) => i !== index)); - setCareerErrors((prevErrors) => { - const updatedErrors = { ...prevErrors }; - delete updatedErrors.careerResume?.[index]; - return updatedErrors; - }); + const formatExperience = (years: number) => { + if (isNaN(years)) return '경력 무관'; + if (years === 0) return '신입'; + if (years >= 10) return '10년 이상'; + return `${years}년`; }; return ( -
-

Career List

- {careerList.map((career, index) => ( -
-

Career {index + 1}

-
- - handleChange(index, e)} - style={{ borderColor: careerErrors.careerResume?.[index]?.company_name ? 'red' : '' }} - /> - {careerErrors.careerResume?.[index]?.company_name && ( -

{careerErrors.careerResume[index].company_name}

- )} -
-
- - handleChange(index, e)} - style={{ borderColor: careerErrors.careerResume?.[index]?.department ? 'red' : '' }} - /> -
-
- - -
-
- - handleChange(index, e)} - style={{ borderColor: careerErrors.careerResume?.[index]?.start_date ? 'red' : '' }} - /> -
-
- - handleChange(index, e)} - style={{ borderColor: careerErrors.careerResume?.[index]?.end_date ? 'red' : '' }} - /> -
- -
-
- ))} - +
+

경력

+
+ {value[0] === value[1] + ? formatExperience(value[0]) + : `${formatExperience(value[0])} ~ ${formatExperience(value[1])}`} +
+
+ 'Temperature range'} + value={value} + onChange={handleChange} + valueLabelDisplay="auto" + min={0} + max={10} + step={1} + marks={[ + { value: 0, label: '신입' }, + { value: 10, label: '10년 이상' }, + ]} + sx={{ + '& .MuiSlider-track': { + height: 4, + backgroundColor: '#2563eb', + }, + '& .MuiSlider-rail': { + height: 4, + backgroundColor: '#e5e7eb', + }, + '& .MuiSlider-thumb': { + width: 20, + height: 20, + backgroundColor: '#2563eb', + '&:hover, &.Mui-focusVisible': { + boxShadow: '0 0 0 8px rgba(37, 99, 235, 0.16)', + }, + }, + }} + /> +
); }; -export default CareerResumeForm; +export default Experience; From 9b243764963d3a07250703c9726b2dd7a7de1750 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 27 Nov 2024 19:55:40 +0900 Subject: [PATCH 2/5] =?UTF-8?q?refactor:=20console.log=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/saramin/route.ts | 2 -- src/app/recruit/page.tsx | 1 + src/components/recruit/category/Experience.tsx | 2 +- src/components/recruit/joblist.tsx | 2 -- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/api/saramin/route.ts b/src/api/saramin/route.ts index bd6deb7..4a154ea 100644 --- a/src/api/saramin/route.ts +++ b/src/api/saramin/route.ts @@ -30,9 +30,7 @@ export async function fetchJobs( params: FetchJobsParams, ): Promise<{ jobs: Job[]; totalPages: number }> { try { - console.log('Fetching jobs with params:', params); const response = await axios.get(`${baseUrl}job-info`, { params }); - // console.log('API response:', response.data); return { jobs: response.data.data.content, totalPages: response.data.data.totalPages, diff --git a/src/app/recruit/page.tsx b/src/app/recruit/page.tsx index 96fa096..11f5a91 100644 --- a/src/app/recruit/page.tsx +++ b/src/app/recruit/page.tsx @@ -64,6 +64,7 @@ const RecruitPage: React.FC = () => { currentPage={currentPage} totalPages={totalPages} onPageChange={handlePageChange} + isLoading={false} />
diff --git a/src/components/recruit/category/Experience.tsx b/src/components/recruit/category/Experience.tsx index 674430a..1be7486 100644 --- a/src/components/recruit/category/Experience.tsx +++ b/src/components/recruit/category/Experience.tsx @@ -50,7 +50,7 @@ const Experience: React.FC = ({ step={1} marks={[ { value: 0, label: '신입' }, - { value: 10, label: '10년 이상' }, + { value: 10, label: '10년' }, ]} sx={{ '& .MuiSlider-track': { diff --git a/src/components/recruit/joblist.tsx b/src/components/recruit/joblist.tsx index 61c6908..46016b1 100644 --- a/src/components/recruit/joblist.tsx +++ b/src/components/recruit/joblist.tsx @@ -6,8 +6,6 @@ import ReactPaginate from 'react-paginate'; import { Job } from './job'; -// import { fetchJobs } from '@/api/saramin/route'; - function cleanLocationNames(locationNames: string[]): string[] { const uniqueLocations = new Set( locationNames.flatMap((name) => name.split(' > ')).filter((name) => name !== '>'), From 16b153ec90b7cf3347ab6634e946e042909d22e9 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 27 Nov 2024 20:18:39 +0900 Subject: [PATCH 3/5] =?UTF-8?q?design:=20=ED=95=B8=EB=93=A4=20=ED=81=AC?= =?UTF-8?q?=EA=B8=B0=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/recruit/category/Experience.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/recruit/category/Experience.tsx b/src/components/recruit/category/Experience.tsx index 1be7486..5691f21 100644 --- a/src/components/recruit/category/Experience.tsx +++ b/src/components/recruit/category/Experience.tsx @@ -62,8 +62,8 @@ const Experience: React.FC = ({ backgroundColor: '#e5e7eb', }, '& .MuiSlider-thumb': { - width: 20, - height: 20, + width: 15, + height: 15, backgroundColor: '#2563eb', '&:hover, &.Mui-focusVisible': { boxShadow: '0 0 0 8px rgba(37, 99, 235, 0.16)', From 4753c6c59f7d334d277abaa56df0e2a452f1018d Mon Sep 17 00:00:00 2001 From: moko Date: Tue, 3 Dec 2024 11:31:39 +0900 Subject: [PATCH 4/5] =?UTF-8?q?fixed:=20=EB=AA=A8=EB=8B=AC=20=EC=97=B4?= =?UTF-8?q?=EA=B3=A0=20=EB=8B=AB=EC=9D=84=20=EC=8B=9C=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EB=A9=88=EC=B6=A4=20=ED=95=B4=EA=B2=B0=20refactor:?= =?UTF-8?q?=20=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80=20UI=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/logo.png | Bin 0 -> 3773 bytes public/profile.png | Bin 0 -> 2537 bytes src/app/profile/page.tsx | 51 +------ src/components/mypage/mypageContainer.tsx | 159 ++++++++++++++++++++++ src/components/portal/modal.tsx | 21 ++- 5 files changed, 175 insertions(+), 56 deletions(-) create mode 100644 public/logo.png create mode 100644 public/profile.png create mode 100644 src/components/mypage/mypageContainer.tsx diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7828ed5fb1ad2c6bf3c1f2dcb26c8d0d983e1599 GIT binary patch literal 3773 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 literal 0 HcmV?d00001 diff --git a/public/profile.png b/public/profile.png new file mode 100644 index 0000000000000000000000000000000000000000..a4c83fc67a49263be20b886ec730851fbc4aded5 GIT binary patch literal 2537 zcmVPPv@#Ctqg77ZG1XW+R-lcK7b~77)A%fXDFn+E+;Q-m@>P z@5l|pIci_u-MvGq{KL0`@b)v$t!|$i0KWWkcY}rg3?5;tL@yLLCyfQY36Hq(oHx!5 z0049ZkG$d0IRfBp+9d#R!P_MOaKYOp0C2(Eg$H1SGj1=w_~S9`;TRsWeeuQq`cqFm zeC7V1{|<2VYMbZG_5z|f?dW~3;BLTU)?RsK4X?g_1+G4Uw+A?bX3AIDxI7P!Vf*&m z3GVUlrI**Ap9u%B@^5i>43Ba9=9>vV`sl&gkRSpc!#QZ5e7rpy00`(9&Plth1K@(U zO90@4w@U!vg11Wm;DWc@4HD7OZnwLMh}Yv;trbft)c3U(eh#qTSN;KPw?Nwm01xzf4@{VA)ld+^@_dB4e63X}bo48~mUIp*CyV)3VP?>#p}`G1;3F;oRNClyal2!8tw z_($~1&lUgoe}wzL5Z%Ae{jU>l_}ykB!V>QJ+eyISzD`TQ`-UR2NRO$74|fD;;CK8t zE*Yn96-SzlLBz$JIN_83K=|#0S63ihm&|ws%g=G-~1amvKFs)W%X}(@* ztSJcV6$IAVP<*3W|)WrDV0gQI(HzA05i+ab+zXd*7uxkp5!R%Tzo%_ zXz^}tuhw6$r3PScnOO5`xCw6z%mp&W0C4F=X$qe;kC^+SOU$DRA|A+`9`ck{hhTpf zwHt)-V8j`!r@)wj;>CoZccI6B-%aie2GY&;w3jIC!EhnRKtr0*`!R7xx1ePw}gPg?IE3a%XBsZ}|CFb{p z!U1arfU7<=g z{w-UD>snDG@t|3ND61yw@8LiTAk1^B@tLJUj(Y}2lxHBOy)eFK1=e2bf%Te*OJkJM zm_0x<0#!GYE2u(LNTSNHb2Z6&x2_VNmBaHq7e-ZYRcOqY#1Li;SxP)s%R%=zDRdSf z#GKSZfYWzHuM7?0BBUk+$d(lzU=LvTE@}-+j}{(6hO9hs2;fv5OlrOBYXwnDU6~bH zQ4}OkILm)c-bR%k6~*6|s8`%-qqyS2!g#>y85Xs|Y|~NP1I4`uCO(dTwNh+SiWA;$ zrJEw&3$W!U%>cYLphzm@p@@cj@zmI?iXn$Nw$;A|6!pqRq@bsU;;tUvpzCPXLXDVF z1g&$G`&s~?+LF1&3rve@ zu^|ULjqa+KID8Ukc4xrB3}@a(;9hlLQFpo$)DNIj4V zTRBGR1Gc(^*;tJ~l>91Tfaoc_l{_u*qL}rNr1%#)EVCB|qiQ7xk*OT5s3Y8eOmg>t zrQ*{2*7smT=uj8^jFRHaKos{3L5_yZXQVYylM^88bDDXZM?n|<5C#bMra4$$?rWPr zPooY{oK19`!0Br|a0Jz}PcGcIh*RmN8eZ$Ew@6XTfxrt6=w+)jy;XkHQlA$|RMTZ6 z=DU-q;DQ=kVeFE_LdJGF z(=#!s`$sr9C`rdYuN{tM(Qk}Ql~Q+vS?UeVI(a;o$3=AmhhT`EU{>FpNz*qg=gyG))JYX>Oqppd zj|K}yws7$=O&`lhXpNkXe&Uag77Cy8fX1P-XR}Zt>RcLU96mdwiy;ND#Z~8pVZq3Y ze%)8aP@t7ah~0JbBJAOx>E*a_-SU(0)g5t1@}rr&&YucEv2n4VJ#WwSh#T8@I|BDP za}PmoM6V)SSUC9w8BqEGWmH+}^^n$B_SwQ;d=agvGThRcDAxm((T;Ly`jGbmzrIK1 z$(seQT<=m*7Xn7%?q-p*!FU~W1vu4bc+)au7Vj6&gI$r@Ep@Mbo9p!hW*wXL1Y~V- zcwK)$x367$;yZnD@80*vKv&-`Wq6HW{c9;BLce3DMe<2%ccD8!?bA{;L|O{uyUMIQ zTb+L@5@Dv`UufvrB*8-XoR917T)VdZK;HijiRc}vm*ZvF00000NkvXXu0mjf*$%=_ literal 0 HcmV?d00001 diff --git a/src/app/profile/page.tsx b/src/app/profile/page.tsx index d28eda8..271ccbe 100644 --- a/src/app/profile/page.tsx +++ b/src/app/profile/page.tsx @@ -1,53 +1,6 @@ 'use client'; -import { useAtom } from 'jotai'; -import Image from 'next/image'; -import { FaRegUserCircle } from 'react-icons/fa'; - -import { loadingAtom } from '@/atoms/formAtoms'; -import useUser from '@/hooks/mypage/useUser'; -import { useModal } from '@/lib/context/ModalContext'; -import { accessTokenAtom } from '@/store/useTokenStore'; - +import MyPageContainer from '@/components/mypage/mypageContainer'; export default function Profile() { - const [accessToken] = useAtom(accessTokenAtom); - const { openModal } = useModal(); - const { user, userLogout } = useUser(accessToken ?? ''); - const [loading] = useAtom(loadingAtom); - return ( -
-
-
-
- {user?.imageUrl ? ( - profileImage - ) : ( - - )} -
- {user?.nickname} - {user?.email} -
-
-
- -
-
-
-
- - -
-
-
- ); + return ; } diff --git a/src/components/mypage/mypageContainer.tsx b/src/components/mypage/mypageContainer.tsx new file mode 100644 index 0000000..b64f02d --- /dev/null +++ b/src/components/mypage/mypageContainer.tsx @@ -0,0 +1,159 @@ +'use client'; + +import { useAtom } from 'jotai'; +import Image from 'next/image'; + +import { loadingAtom } from '@/atoms/formAtoms'; +import useUser from '@/hooks/mypage/useUser'; +import { accessTokenAtom } from '@/store/useTokenStore'; +import profile from '../../../public/profile.png'; +import { useState } from 'react'; + +export default function MyPageContainer() { + const [accessToken] = useAtom(accessTokenAtom); + const { user, userLogout } = useUser(accessToken ?? ''); + const [loading] = useAtom(loadingAtom); + const [isEdit, setIsEdit] = useState({ + myProfile: false, + default: false, + }); + const [nickname, setNickname] = useState(user?.nickname ?? ''); + const [password, setPassword] = useState(''); + + const onStartEdit = (type: 'myProfile' | 'default') => { + setIsEdit((prev) => ({ ...prev, [type]: true })); + }; + const onFinishEdit = () => { + // 프로필 이미지, 닉네임 수정 + }; + const onCancelEdit = (type: 'myProfile' | 'default') => { + setIsEdit((prev) => ({ ...prev, [type]: false })); + }; + + return ( +
+
+

내 프로필

+
+
+

이미지

+ {isEdit.myProfile ? ( +
+
+ {user?.imageUrl ? ( + profileImage + ) : ( + emptyImage + )} +
+ + +
+ ) : ( + <> + {' '} +
+ {user?.imageUrl ? ( + profileImage + ) : ( + emptyImage + )} +
+ + )} +
+
+

닉네임

+ {isEdit.myProfile ? ( +
+ { + setNickname(e.target.value); + }} + placeholder={user?.nickname} + className="border-Grey-200" + /> + +
+ ) : ( + {user?.nickname} + )} +
+
+
+

계정

+ {user?.email} +
+ {isEdit.myProfile ? ( +
+ + +
+ ) : ( + + )} +
+
+
+
+

기본 정보

+
+
+
+

비밀번호

+ {isEdit.default ? ( + setPassword(e.target.value)} + placeholder="비밀번호를 입력하세요." + className="border-Grey-200 text-[14px]" + /> + ) : ( +
비밀번호 설정
+ )} +
+ {isEdit.default ? ( +
+ + +
+ ) : ( + + )} +
+
+
+ +
+ ); +} diff --git a/src/components/portal/modal.tsx b/src/components/portal/modal.tsx index d6a641c..f475246 100644 --- a/src/components/portal/modal.tsx +++ b/src/components/portal/modal.tsx @@ -12,17 +12,24 @@ interface ModalProps { const Modal = ({ isOpen, onClose, children }: ModalProps) => { useEffect(() => { - if (isOpen) { - const currentOverflow = document.body.style.overflow; - if (currentOverflow !== 'hidden') { + const handleBodyScroll = () => { + const modalElements = document.querySelectorAll('[data-modal]'); + if (modalElements.length > 0) { document.body.style.overflow = 'hidden'; + } else { + document.body.style.overflow = ''; } + }; + + if (isOpen) { + handleBodyScroll(); } + return () => { - const modalCount = document.querySelectorAll('[data-modal]').length; - if (modalCount === 1) { - document.body.style.overflow = 'unset'; - } + // setTimeout을 사용하여 DOM 업데이트 후 스크롤 상태 확인 + setTimeout(() => { + handleBodyScroll(); + }, 0); }; }, [isOpen]); From 8ffa570c3d493ed76c4067d55b1e487303876d99 Mon Sep 17 00:00:00 2001 From: moko Date: Tue, 3 Dec 2024 12:33:49 +0900 Subject: [PATCH 5/5] =?UTF-8?q?fixed:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20api=20=EC=97=B0=EA=B2=B0=20chore:=20toast?= =?UTF-8?q?=20install?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 24 +++ package.json | 1 + src/api/mypage/mypage.action.ts | 68 +++++-- src/app/layout.tsx | 11 ++ src/components/common/Modals.tsx | 3 - src/components/mypage/editProfileModal.tsx | 211 --------------------- src/components/mypage/mypageContainer.tsx | 202 +++++++++++++++++--- 7 files changed, 265 insertions(+), 255 deletions(-) delete mode 100644 src/components/mypage/editProfileModal.tsx diff --git a/package-lock.json b/package-lock.json index 0f7bbd2..0dd4090 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,7 @@ "react": "^18", "react-dom": "^18", "react-hook-form": "^7.52.1", + "react-hot-toast": "^2.4.1", "react-icons": "^5.3.0", "react-markdown": "^9.0.1", "react-modal": "^3.16.1", @@ -11331,6 +11332,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/goober": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", + "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.0.1", "license": "MIT", @@ -19038,6 +19047,21 @@ "react": "^16.8.0 || ^17 || ^18 || ^19" } }, + "node_modules/react-hot-toast": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz", + "integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==", + "dependencies": { + "goober": "^2.1.10" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-icons": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz", diff --git a/package.json b/package.json index dcfe343..5be1f5e 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "react": "^18", "react-dom": "^18", "react-hook-form": "^7.52.1", + "react-hot-toast": "^2.4.1", "react-icons": "^5.3.0", "react-markdown": "^9.0.1", "react-modal": "^3.16.1", diff --git a/src/api/mypage/mypage.action.ts b/src/api/mypage/mypage.action.ts index a538fdd..3c15cd9 100644 --- a/src/api/mypage/mypage.action.ts +++ b/src/api/mypage/mypage.action.ts @@ -1,5 +1,8 @@ +import axios from 'axios'; import instance from '../axiosInstance'; +const BASE_URL = process.env.NEXT_PUBLIC_API_URL; + export const getUser = async (accessToken: string) => { const user = await instance.get('/user', { headers: { @@ -10,22 +13,63 @@ export const getUser = async (accessToken: string) => { return user; }; -export const checkNickname = async () => { - const res = await instance.get('/mypage/checkDuplicateNickname'); - console.log(res); +export const checkNickname = async (nickname: string, accessToken: string) => { + const res = await axios.get(`${BASE_URL}/mypage/checkDuplicateNickname`, { + params: { + nickname, + }, + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + return res; }; -export const editNickname = async () => { - const res = await instance.patch('/mypage/nickname'); - console.log(res); +export const editNickname = async (nickname: string, accessToken: string) => { + const res = await axios.patch( + `${BASE_URL}/mypage/nickname`, + { nickname }, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }, + ); + return res.data; }; -export const editPassword = async () => { - const res = await instance.patch('/mypage/password'); - console.log(res); +export const editPassword = async (password: string, accessToken: string) => { + const res = await axios.patch( + `${BASE_URL}/mypage/password`, + { password }, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }, + ); + return res.data; }; -export const editProfileImage = async () => { - const res = await instance.patch('/mypage/profileImage'); - console.log(res); +export const updateProfileImage = async (file: File, accessToken: string) => { + const formData = new FormData(); + formData.append('file', file); + + const res = await axios.patch(`${BASE_URL}/api/mypage/profileImage`, formData, { + headers: { + 'Content-Type': 'multipart/form-data', + Authorization: `Bearer ${accessToken}`, + }, + }); + return res.data; +}; + +export const logout = async (accessToken: string) => { + const res = await axios.delete(`${BASE_URL}/user/logout`, { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + console.log('logout', res.data); + return res.data; }; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 150c5ba..27f61fa 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -8,6 +8,7 @@ import { ModalProvider } from '@/lib/context/ModalContext'; import './globals.css'; // eslint-disable-next-line import/order import MobileHeader from '@/components/common/mobileHeader'; +import { Toaster } from 'react-hot-toast'; // pretendard 함수 관련 에러로 500이 떠서 일단 주석 처리 interface RootLayoutProps { @@ -72,6 +73,16 @@ export default function RootLayout({ children }: RootLayoutProps) {
{children}
{!shouldHideHeaderAndFooter &&