From d5c6d13cde5b42a229001ef24d7e0b32ce93a185 Mon Sep 17 00:00:00 2001 From: junghongseop Date: Tue, 16 Jul 2024 20:12:17 +0900 Subject: [PATCH 1/6] =?UTF-8?q?chore(user):=20react-image-crop=20=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/user/package.json | 3 +- pnpm-lock.yaml | 297 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 294 insertions(+), 6 deletions(-) diff --git a/apps/user/package.json b/apps/user/package.json index 24510ef90..9dad1f777 100644 --- a/apps/user/package.json +++ b/apps/user/package.json @@ -33,9 +33,9 @@ "typescript": "5.1.3" }, "dependencies": { + "@maru/design-token": "workspace:*", "@maru/hooks": "workspace:*", "@maru/icon": "workspace:*", - "@maru/design-token": "workspace:*", "@maru/ui": "workspace:*", "@maru/utils": "workspace:*", "@suspensive/react": "^1.18.1", @@ -50,6 +50,7 @@ "react": "18.2.0", "react-daum-postcode": "^3.1.3", "react-dom": "18.2.0", + "react-easy-crop": "^5.0.7", "recoil": "^0.7.7", "styled-components": "^6.0.3" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a1f85f2b..f4b50a326 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -207,7 +207,7 @@ importers: version: 1.11.8 next: specifier: 13.5.2 - version: 13.5.2(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0) + version: 13.5.2(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0) react: specifier: 18.2.0 version: 18.2.0 @@ -217,6 +217,9 @@ importers: react-dom: specifier: 18.2.0 version: 18.2.0(react@18.2.0) + react-easy-crop: + specifier: ^5.0.7 + version: 5.0.7(react-dom@18.2.0)(react@18.2.0) recoil: specifier: ^0.7.7 version: 0.7.7(react-dom@18.2.0)(react@18.2.0) @@ -787,6 +790,21 @@ packages: - supports-color dev: true + /@babel/helper-define-polyfill-provider@0.4.2(@babel/core@7.22.5): + resolution: {integrity: sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-compilation-targets': 7.22.10 + '@babel/helper-plugin-utils': 7.22.5 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.2 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-environment-visitor@7.22.5: resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} engines: {node: '>=6.9.0'} @@ -895,6 +913,18 @@ packages: '@babel/helper-wrap-function': 7.22.10 dev: true + /@babel/helper-remap-async-to-generator@7.22.9(@babel/core@7.22.5): + resolution: {integrity: sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-wrap-function': 7.22.10 + dev: true + /@babel/helper-replace-supers@7.22.5: resolution: {integrity: sha512-aLdNM5I3kdI/V9xGNyKSF3X/gTyMUBohTZ+/3QdQKAA9vxIiy12E+8E2HoOP1/DjeqU+g6as35QHJNMDDYpuCg==} engines: {node: '>=6.9.0'} @@ -1598,6 +1628,19 @@ packages: '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.10) dev: true + /@babel/plugin-transform-async-generator-functions@7.22.10(@babel/core@7.22.5): + resolution: {integrity: sha512-eueE8lvKVzq5wIObKK/7dvoeKJ+xc6TvRn6aysIjS6pSCeLy7S/eVi7pEQknZqyqvzaNKdDtem8nUNTBgDVR2g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.9(@babel/core@7.22.5) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.5) + dev: true + /@babel/plugin-transform-async-generator-functions@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-gGOEvFzm3fWoyD5uZq7vVTD57pPJ3PczPUD/xCFGjzBpUosnklmXyKnGQbbbGs1NPNPskFex0j93yKbHt0cHyg==} engines: {node: '>=6.9.0'} @@ -1668,6 +1711,16 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true + /@babel/plugin-transform-block-scoping@7.22.10(@babel/core@7.22.5): + resolution: {integrity: sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + /@babel/plugin-transform-block-scoping@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==} engines: {node: '>=6.9.0'} @@ -1768,6 +1821,26 @@ packages: - supports-color dev: true + /@babel/plugin-transform-classes@7.22.6(@babel/core@7.22.5): + resolution: {integrity: sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.22.10 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-function-name': 7.22.5 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/plugin-transform-computed-properties@7.22.5(@babel/core@7.22.10): resolution: {integrity: sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==} engines: {node: '>=6.9.0'} @@ -1799,6 +1872,16 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true + /@babel/plugin-transform-destructuring@7.22.10(@babel/core@7.22.5): + resolution: {integrity: sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + /@babel/plugin-transform-destructuring@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==} engines: {node: '>=6.9.0'} @@ -2317,6 +2400,18 @@ packages: '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.10) dev: true + /@babel/plugin-transform-optional-chaining@7.22.10(@babel/core@7.22.5): + resolution: {integrity: sha512-MMkQqZAZ+MGj+jGTG3OTuhKeBpNcO+0oCEbrGNEaOmiEn+1MzRyQlYsruGiU8RTK3zV6XwrVJTmwiDOyYK6J9g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.5) + dev: true + /@babel/plugin-transform-optional-chaining@7.22.5(@babel/core@7.22.10): resolution: {integrity: sha512-AconbMKOMkyG+xCng2JogMCDcqW8wedQAqpVIL4cOSescZ7+iW8utC6YDZLMCSUIReEA733gzRSaOSXMAt/4WQ==} engines: {node: '>=6.9.0'} @@ -2529,6 +2624,17 @@ packages: regenerator-transform: 0.15.2 dev: true + /@babel/plugin-transform-regenerator@7.22.10(@babel/core@7.22.5): + resolution: {integrity: sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + regenerator-transform: 0.15.2 + dev: true + /@babel/plugin-transform-regenerator@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==} engines: {node: '>=6.9.0'} @@ -2711,6 +2817,16 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true + /@babel/plugin-transform-unicode-escapes@7.22.10(@babel/core@7.22.5): + resolution: {integrity: sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + /@babel/plugin-transform-unicode-escapes@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==} engines: {node: '>=6.9.0'} @@ -2874,6 +2990,97 @@ packages: - supports-color dev: true + /@babel/preset-env@7.22.10(@babel/core@7.22.5): + resolution: {integrity: sha512-riHpLb1drNkpLlocmSyEg4oYJIQFeXAK/d7rI6mbD0XsvoTOOweXDmQPG/ErxsEhWk3rl3Q/3F6RFQlVFS8m0A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.22.20 + '@babel/core': 7.22.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.22.15 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.22.5) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.5) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.5) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.5) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.5) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.5) + '@babel/plugin-syntax-import-assertions': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-syntax-import-attributes': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.5) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.5) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.5) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.5) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.5) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.5) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.5) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.5) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.5) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.5) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.22.5) + '@babel/plugin-transform-arrow-functions': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-async-generator-functions': 7.22.10(@babel/core@7.22.5) + '@babel/plugin-transform-async-to-generator': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-block-scoped-functions': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-block-scoping': 7.22.10(@babel/core@7.22.5) + '@babel/plugin-transform-class-properties': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-class-static-block': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-classes': 7.22.6(@babel/core@7.22.5) + '@babel/plugin-transform-computed-properties': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-destructuring': 7.22.10(@babel/core@7.22.5) + '@babel/plugin-transform-dotall-regex': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-duplicate-keys': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-dynamic-import': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-exponentiation-operator': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-export-namespace-from': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-for-of': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-function-name': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-json-strings': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-literals': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-logical-assignment-operators': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-member-expression-literals': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-modules-amd': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-modules-commonjs': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-modules-systemjs': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-modules-umd': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-new-target': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-nullish-coalescing-operator': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-numeric-separator': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-object-rest-spread': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-object-super': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-optional-catch-binding': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-optional-chaining': 7.22.10(@babel/core@7.22.5) + '@babel/plugin-transform-parameters': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-private-methods': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-private-property-in-object': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-property-literals': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-regenerator': 7.22.10(@babel/core@7.22.5) + '@babel/plugin-transform-reserved-words': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-shorthand-properties': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-spread': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-sticky-regex': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-template-literals': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-typeof-symbol': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-unicode-escapes': 7.22.10(@babel/core@7.22.5) + '@babel/plugin-transform-unicode-property-regex': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-unicode-regex': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-transform-unicode-sets-regex': 7.22.5(@babel/core@7.22.5) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.22.5) + '@babel/types': 7.22.10 + babel-plugin-polyfill-corejs2: 0.4.5(@babel/core@7.22.5) + babel-plugin-polyfill-corejs3: 0.8.3(@babel/core@7.22.5) + babel-plugin-polyfill-regenerator: 0.5.2(@babel/core@7.22.5) + core-js-compat: 3.31.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/preset-env@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==} engines: {node: '>=6.9.0'} @@ -2999,6 +3206,17 @@ packages: esutils: 2.0.3 dev: true + /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.22.5): + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/types': 7.22.10 + esutils: 2.0.3 + dev: true + /@babel/preset-react@7.22.5(@babel/core@7.22.10): resolution: {integrity: sha512-M+Is3WikOpEJHgR385HbuCITPTaPRaNkibTEa9oiofmJvIsrceb4yp9RL9Kb+TE8LznmeyZqpP+Lopwcx59xPQ==} engines: {node: '>=6.9.0'} @@ -5434,7 +5652,7 @@ packages: hasBin: true dependencies: '@babel/core': 7.22.10 - '@babel/preset-env': 7.22.10(@babel/core@7.22.10) + '@babel/preset-env': 7.22.10(@babel/core@7.22.5) '@babel/types': 7.22.10 '@ndelangen/get-tarball': 3.0.9 '@storybook/codemod': 7.3.1 @@ -5794,7 +6012,7 @@ packages: fs-extra: 11.1.1 image-size: 1.0.2 loader-utils: 3.2.1 - next: 13.5.2(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0) + next: 13.5.2(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0) node-polyfill-webpack-plugin: 2.0.1(webpack@5.88.2) pnp-webpack-plugin: 1.7.0(typescript@5.1.3) postcss: 8.4.24 @@ -7689,6 +7907,19 @@ packages: - supports-color dev: true + /babel-plugin-polyfill-corejs2@0.4.5(@babel/core@7.22.5): + resolution: {integrity: sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/compat-data': 7.22.9 + '@babel/core': 7.22.5 + '@babel/helper-define-polyfill-provider': 0.4.2(@babel/core@7.22.5) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + /babel-plugin-polyfill-corejs3@0.8.1(@babel/core@7.22.5): resolution: {integrity: sha512-ikFrZITKg1xH6pLND8zT14UPgjKHiGLqex7rGEZCH2EvhsneJaJPemmpQaIZV5AL03II+lXylw3UmddDK8RU5Q==} peerDependencies: @@ -7712,6 +7943,18 @@ packages: - supports-color dev: true + /babel-plugin-polyfill-corejs3@0.8.3(@babel/core@7.22.5): + resolution: {integrity: sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-define-polyfill-provider': 0.4.2(@babel/core@7.22.5) + core-js-compat: 3.31.0 + transitivePeerDependencies: + - supports-color + dev: true + /babel-plugin-polyfill-regenerator@0.5.0(@babel/core@7.22.5): resolution: {integrity: sha512-hDJtKjMLVa7Z+LwnTCxoDLQj6wdc+B8dun7ayF2fYieI6OzfuvcLMB32ihJZ4UhCBwNYGl5bg/x/P9cMdnkc2g==} peerDependencies: @@ -7733,6 +7976,17 @@ packages: - supports-color dev: true + /babel-plugin-polyfill-regenerator@0.5.2(@babel/core@7.22.5): + resolution: {integrity: sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.22.5 + '@babel/helper-define-polyfill-provider': 0.4.2(@babel/core@7.22.5) + transitivePeerDependencies: + - supports-color + dev: true + /babel-plugin-react-docgen@4.2.1: resolution: {integrity: sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==} dependencies: @@ -12335,7 +12589,7 @@ packages: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: true - /next@13.5.2(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0): + /next@13.5.2(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-vog4UhUaMYAzeqfiAAmgB/QWLW7p01/sg+2vn6bqc/CxHFYizMzLv6gjxKzl31EVFkfl/F+GbxlKizlkTE9RdA==} engines: {node: '>=16.14.0'} hasBin: true @@ -12357,7 +12611,7 @@ packages: postcss: 8.4.14 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.1(@babel/core@7.22.10)(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.22.5)(react@18.2.0) watchpack: 2.4.0 zod: 3.21.4 optionalDependencies: @@ -12552,6 +12806,10 @@ packages: engines: {node: '>=0.10.0'} requiresBuild: true + /normalize-wheel@1.0.1: + resolution: {integrity: sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==} + dev: false + /npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} @@ -13490,6 +13748,18 @@ packages: react: 18.2.0 scheduler: 0.23.0 + /react-easy-crop@5.0.7(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-6d5IUt09M3HwdDGwrcjPVgfrOfYWAOku8sCTn/xU7b1vkEg+lExMLwW8UbR39L8ybQi0hJZTU57yprF9h5Q5Ig==} + peerDependencies: + react: '>=16.4.0' + react-dom: '>=16.4.0' + dependencies: + normalize-wheel: 1.0.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tslib: 2.6.2 + dev: false + /react-element-to-jsx-string@15.0.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==} peerDependencies: @@ -14634,6 +14904,23 @@ packages: client-only: 0.0.1 react: 18.2.0 + /styled-jsx@5.1.1(@babel/core@7.22.5)(react@18.2.0): + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + dependencies: + '@babel/core': 7.22.5 + client-only: 0.0.1 + react: 18.2.0 + /styled-reset@4.4.7(styled-components@6.0.3): resolution: {integrity: sha512-OxtLqP9/2mXoI8WYa0NrJuTyvVziT+fi0Dp8go5CgTGzSVPQVo5ggaxl1tK+l08ynrVImKswSiDJFaVHxBKJuQ==} engines: {node: '>=16.0.0'} From b663673b439409c7bbcc7670e297f84c02b6d65d Mon Sep 17 00:00:00 2001 From: junghongseop Date: Wed, 17 Jul 2024 01:10:35 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat(user):=20=EC=82=AC=EC=A7=84=EC=9D=84?= =?UTF-8?q?=20117*156=EC=82=AC=EC=9D=B4=EC=A6=88=EB=A1=9C=20=EC=9E=90?= =?UTF-8?q?=EB=A5=B4=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/user/src/utils/cropImage.ts | 68 ++++++++++++++++++++++++++++++++ apps/user/src/utils/index.ts | 1 + 2 files changed, 69 insertions(+) create mode 100644 apps/user/src/utils/cropImage.ts diff --git a/apps/user/src/utils/cropImage.ts b/apps/user/src/utils/cropImage.ts new file mode 100644 index 000000000..cbadec9f6 --- /dev/null +++ b/apps/user/src/utils/cropImage.ts @@ -0,0 +1,68 @@ +const createImage = (url: string): Promise => + new Promise((resolve, reject) => { + const image = new Image(); + image.addEventListener('load', () => resolve(image)); + image.addEventListener('error', (error) => reject(error)); + image.setAttribute('crossOrigin', 'anonymous'); + image.src = url; + }); + +interface PixelCrop { + x: number; + y: number; + width: number; + height: number; +} + +export const getCroppedImg = async ( + imageSrc: string, + pixelCrop: PixelCrop, + outputWidth = 117, + outputHeight = 156 +) => { + const image = await createImage(imageSrc); + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + canvas.width = outputWidth * 2; + canvas.height = outputHeight * 2; + + if (!ctx) { + throw new Error('Canvas 2D context not available'); + } + + ctx.imageSmoothingEnabled = true; + ctx.imageSmoothingQuality = 'high'; + + ctx.drawImage( + image, + pixelCrop.x, + pixelCrop.y, + pixelCrop.width, + pixelCrop.height, + 0, + 0, + outputWidth * 2, + outputHeight * 2 + ); + + const downscaledCanvas = document.createElement('canvas'); + const downscaledCtx = downscaledCanvas.getContext('2d'); + + downscaledCanvas.width = outputWidth; + downscaledCanvas.height = outputHeight; + + if (!downscaledCtx) { + throw new Error('Canvas 2D context not available'); + } + + downscaledCtx.drawImage(canvas, 0, 0, outputWidth, outputHeight); + + return new Promise((resolve) => { + downscaledCanvas.toBlob((blob) => { + if (blob) { + resolve(URL.createObjectURL(blob)); + } + }, 'image/jpeg'); + }); +}; diff --git a/apps/user/src/utils/index.ts b/apps/user/src/utils/index.ts index c7c58c0a0..51966c92e 100644 --- a/apps/user/src/utils/index.ts +++ b/apps/user/src/utils/index.ts @@ -5,3 +5,4 @@ export { default as updateSlicedSubjectList } from './updateSlicedSubjectList'; export { default as formatApplicationDate } from './formatApplicationDate'; export { default as formatStartDate } from './formatStartDate'; export { formatStatus } from './formatStatus'; +export { getCroppedImg } from './cropImage'; From 01f1900f556c79e8fca37e10ecc29647ff84d69a Mon Sep 17 00:00:00 2001 From: junghongseop Date: Wed, 17 Jul 2024 01:12:13 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat(user):=20=EC=82=AC=EC=A7=84=EC=9D=84?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9=EC=9E=90=EA=B0=80=20=EC=9B=90=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=8C=80=EB=A1=9C=20=EC=9E=90=EB=A5=B4=EB=8A=94=20?= =?UTF-8?q?=EB=AA=A8=EB=8B=AC=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../form/CropImageModal/CropImageModal.tsx | 100 ++++++++++++++++++ apps/user/src/components/form/index.ts | 1 + 2 files changed, 101 insertions(+) create mode 100644 apps/user/src/components/form/CropImageModal/CropImageModal.tsx diff --git a/apps/user/src/components/form/CropImageModal/CropImageModal.tsx b/apps/user/src/components/form/CropImageModal/CropImageModal.tsx new file mode 100644 index 000000000..ea4f47c6e --- /dev/null +++ b/apps/user/src/components/form/CropImageModal/CropImageModal.tsx @@ -0,0 +1,100 @@ +import React, { useState, useCallback } from 'react'; +import { color } from '@maru/design-token'; +import { Button, Column, Text } from '@maru/ui'; +import { flex } from '@maru/utils'; +import styled from 'styled-components'; +import type { Area } from 'react-easy-crop'; +import Cropper from 'react-easy-crop'; +import { getCroppedImg } from '@/utils'; + +interface Props { + isOpen: boolean; + imageSrc: string; + onClose: () => void; + onCropComplete: (croppedImage: Blob) => void; +} + +const CropImageModal = ({ isOpen, imageSrc, onClose, onCropComplete }: Props) => { + const [crop, setCrop] = useState({ x: 0, y: 0 }); + const [croppedArea, setCroppedArea] = useState(null); + + const onCropCompleteInternal = useCallback( + (croppedArea: Area, croppedAreaPixels: Area) => { + setCroppedArea(croppedAreaPixels); + }, + [] + ); + + const applyCrop = useCallback(async () => { + if (!croppedArea) return; + const croppedImage = await getCroppedImg(imageSrc, croppedArea, 117, 156); + + const response = await fetch(croppedImage as string); + const blob = await response.blob(); + + onCropComplete(blob); + onClose(); + }, [imageSrc, croppedArea, onCropComplete, onClose]); + + if (!isOpen) return null; + + return ( + + + + + + + + + + + ); +}; + +export default CropImageModal; + +const BlurBackground = styled.div` + display: flex; + align-items: center; + justify-content: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100vh; + background: rgba(0, 0, 0, 0.4); + z-index: 1000; +`; + +const ModalContainer = styled.div` + padding: 20px; + border-radius: 10px; + max-width: 466px; + width: 100%; + text-align: center; + height: 357px; +`; + +const CropImageModalStyle = styled.div` + ${flex({ flexDirection: 'column', justifyContent: 'center' })} + width: 100%; + height: 400px; + border-radius: 6px; + border: 3px solid ${color.gray300}; + position: relative; + overflow: hidden; +`; diff --git a/apps/user/src/components/form/index.ts b/apps/user/src/components/form/index.ts index b9712a554..eaa2dee4f 100644 --- a/apps/user/src/components/form/index.ts +++ b/apps/user/src/components/form/index.ts @@ -11,3 +11,4 @@ export { default as GradePreview } from './GradePreview/GradePreview'; export { default as PdfGeneratedLoader } from './PdfGeneratedLoader/PdfGeneratedLoader'; export { default as ProfileUploader } from './ProfileUploader/ProfileUploader'; export { default as ProgressSteps } from './ProgressSteps/ProgressSteps'; +export { default as CropImageModal } from './CropImageModal/CropImageModal'; From 5fcb2477714632aa0b80d2a32171e7785206f28b Mon Sep 17 00:00:00 2001 From: junghongseop Date: Wed, 17 Jul 2024 01:12:45 +0900 Subject: [PATCH 4/6] =?UTF-8?q?fix(user):=20=EC=82=AC=EC=A7=84=EC=9D=84=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=ED=95=98=EA=B3=A0=20=EC=82=AC=EC=9D=B4?= =?UTF-8?q?=EC=A6=88=EA=B0=80=20=EC=95=88=20=EB=A7=9E=EC=9C=BC=EB=A9=B4=20?= =?UTF-8?q?=EC=82=AC=EC=A7=84=20=EC=9E=90=EB=A5=B4=EB=8A=94=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=20=EB=9C=A8=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../form/ProfileUploader/ProfileUploader.tsx | 62 ++++++++++++++++--- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/apps/user/src/components/form/ProfileUploader/ProfileUploader.tsx b/apps/user/src/components/form/ProfileUploader/ProfileUploader.tsx index ec347569c..39bc93cb5 100644 --- a/apps/user/src/components/form/ProfileUploader/ProfileUploader.tsx +++ b/apps/user/src/components/form/ProfileUploader/ProfileUploader.tsx @@ -7,6 +7,7 @@ import { flex } from '@maru/utils'; import type { ChangeEventHandler, DragEvent } from 'react'; import { useState, useEffect } from 'react'; import styled, { css } from 'styled-components'; +import CropImageModal from '../CropImageModal/CropImageModal'; const ProfileUploader = ({ onPhotoUpload, @@ -20,12 +21,14 @@ const ProfileUploader = ({ const [isDragging, setIsDragging] = useState(false); const { openFileUploader: openImageFileUploader, ref: imageUploaderRef } = useOpenFileUploader(); - const { uploadProfileImageMutate } = useUploadProfileImageMutation(); - + const [imageSrc, setImageSrc] = useState(null); + const [isModalOpen, setIsModalOpen] = useState(false); const [imagePreviewUrl, setImagePreviewUrl] = useState( form.applicant.identificationPictureUri ); + const { uploadProfileImageMutate } = useUploadProfileImageMutation(); + const uploadProfileImageFile = (image: FormData) => { uploadProfileImageMutate(image, { onSuccess: (res) => { @@ -46,9 +49,25 @@ const ProfileUploader = ({ const handleImageFileChange: ChangeEventHandler = (e) => { const { files } = e.target; if (!files || files.length === 0) return; - const formData = new FormData(); - formData.append('image', files[0]); - uploadProfileImageFile(formData); + + const file = files[0]; + const img = new Image(); + img.src = URL.createObjectURL(file); + img.onload = () => { + if (img.width < 117 || img.height < 156) { + alert('사진 크기가 너무 작습니다.'); + return; + } + + if (img.width > 117 || img.height > 156) { + setImageSrc(URL.createObjectURL(file)); + setIsModalOpen(true); + } else { + const formData = new FormData(); + formData.append('image', file, 'image.jpg'); + uploadProfileImageFile(formData); + } + }; }; const onDragEnter = (e: DragEvent) => { @@ -71,9 +90,24 @@ const ProfileUploader = ({ const onDrop = (e: DragEvent) => { e.preventDefault(); e.stopPropagation(); - const formData = new FormData(); - formData.append('image', e.dataTransfer.files[0]); - uploadProfileImageFile(formData); + const file = e.dataTransfer.files[0]; + const img = new Image(); + img.src = URL.createObjectURL(file); + img.onload = () => { + if (img.width < 117 || img.height < 156) { + alert('사진 크기가 너무 작습니다.'); + return; + } + + if (img.width > 117 || img.height > 156) { + setImageSrc(URL.createObjectURL(file)); + setIsModalOpen(true); + } else { + const formData = new FormData(); + formData.append('image', file, 'image.jpg'); + uploadProfileImageFile(formData); + } + }; setIsDragging(false); }; @@ -127,6 +161,18 @@ const ProfileUploader = ({ onChange={handleImageFileChange} hidden /> + {imageSrc && ( + setIsModalOpen(false)} + onCropComplete={(croppedImage) => { + const formData = new FormData(); + formData.append('image', croppedImage, 'image.jpg'); + uploadProfileImageFile(formData); + }} + /> + )} ); }; From 18880e142bedd6de3ed22438df0def6602863e1a Mon Sep 17 00:00:00 2001 From: junghongseop Date: Wed, 17 Jul 2024 01:24:18 +0900 Subject: [PATCH 5/6] =?UTF-8?q?fix(user):=20=ED=95=A8=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../form/CropImageModal/CropImageModal.tsx | 18 +++++++++--------- apps/user/src/utils/cropImage.ts | 2 +- apps/user/src/utils/index.ts | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/user/src/components/form/CropImageModal/CropImageModal.tsx b/apps/user/src/components/form/CropImageModal/CropImageModal.tsx index ea4f47c6e..4de74c6be 100644 --- a/apps/user/src/components/form/CropImageModal/CropImageModal.tsx +++ b/apps/user/src/components/form/CropImageModal/CropImageModal.tsx @@ -5,7 +5,7 @@ import { flex } from '@maru/utils'; import styled from 'styled-components'; import type { Area } from 'react-easy-crop'; import Cropper from 'react-easy-crop'; -import { getCroppedImg } from '@/utils'; +import { getCropImg } from '@/utils'; interface Props { isOpen: boolean; @@ -16,25 +16,25 @@ interface Props { const CropImageModal = ({ isOpen, imageSrc, onClose, onCropComplete }: Props) => { const [crop, setCrop] = useState({ x: 0, y: 0 }); - const [croppedArea, setCroppedArea] = useState(null); + const [cropArea, setCropArea] = useState(null); const onCropCompleteInternal = useCallback( - (croppedArea: Area, croppedAreaPixels: Area) => { - setCroppedArea(croppedAreaPixels); + (cropArea: Area, croppedAreaPixels: Area) => { + setCropArea(croppedAreaPixels); }, [] ); - const applyCrop = useCallback(async () => { - if (!croppedArea) return; - const croppedImage = await getCroppedImg(imageSrc, croppedArea, 117, 156); + const handleApplyCrop = useCallback(async () => { + if (!cropArea) return; + const croppedImage = await getCropImg(imageSrc, cropArea, 117, 156); const response = await fetch(croppedImage as string); const blob = await response.blob(); onCropComplete(blob); onClose(); - }, [imageSrc, croppedArea, onCropComplete, onClose]); + }, [imageSrc, cropArea, onCropComplete, onClose]); if (!isOpen) return null; @@ -54,7 +54,7 @@ const CropImageModal = ({ isOpen, imageSrc, onClose, onCropComplete }: Props) => }} /> -