From 72e3f5586f3245d91eaa02b7702fd132f56b4904 Mon Sep 17 00:00:00 2001 From: Gyeongmin Kim Date: Sun, 5 Jan 2025 23:44:43 +0900 Subject: [PATCH 01/11] =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pnpm 설치 eslint 추가 --- eslint.config.js | 12 + package.json | 7 +- pnpm-lock.yaml | 1444 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1462 insertions(+), 1 deletion(-) create mode 100644 eslint.config.js create mode 100644 pnpm-lock.yaml diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..bb72d115 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,12 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import pluginReact from "eslint-plugin-react"; + + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + {files: ["**/*.{js,mjs,cjs,jsx}"]}, + {languageOptions: { globals: globals.browser }}, + pluginJs.configs.recommended, + pluginReact.configs.flat.recommended, +]; \ No newline at end of file diff --git a/package.json b/package.json index 02cd2326..b48a6df6 100644 --- a/package.json +++ b/package.json @@ -21,5 +21,10 @@ "jsdom": "^25.0.0", "vite": "^5.1.0", "vitest": "^2.1.1" - } + }, + "description": "## 기본과제: 더티코드 개선", + "main": "eslint.config.js", + "keywords": [], + "author": "", + "license": "ISC" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..8ffc0941 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1444 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@testing-library/jest-dom': + specifier: ^6.5.0 + version: 6.6.3 + '@testing-library/user-event': + specifier: ^14.5.2 + version: 14.5.2(@testing-library/dom@10.4.0) + '@vitest/ui': + specifier: ^2.1.1 + version: 2.1.8(vitest@2.1.8) + jsdom: + specifier: ^25.0.0 + version: 25.0.1 + vite: + specifier: ^5.1.0 + version: 5.4.11 + vitest: + specifier: ^2.1.1 + version: 2.1.8(@vitest/ui@2.1.8)(jsdom@25.0.1) + +packages: + + '@adobe/css-tools@4.4.1': + resolution: {integrity: sha512-12WGKBQzjUAI4ayyF4IAtfw2QR/IDoqk6jTddXDhtYTJF9ASmoE1zst7cVtP0aL/F1jUJL5r+JxKXKEgHNbEUQ==} + + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/runtime@7.26.0': + resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} + engines: {node: '>=6.9.0'} + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@polka/url@1.0.0-next.28': + resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} + + '@rollup/rollup-android-arm-eabi@4.29.1': + resolution: {integrity: sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.29.1': + resolution: {integrity: sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.29.1': + resolution: {integrity: sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.29.1': + resolution: {integrity: sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.29.1': + resolution: {integrity: sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.29.1': + resolution: {integrity: sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.29.1': + resolution: {integrity: sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.29.1': + resolution: {integrity: sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.29.1': + resolution: {integrity: sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.29.1': + resolution: {integrity: sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.29.1': + resolution: {integrity: sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.29.1': + resolution: {integrity: sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.29.1': + resolution: {integrity: sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.29.1': + resolution: {integrity: sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.29.1': + resolution: {integrity: sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.29.1': + resolution: {integrity: sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.29.1': + resolution: {integrity: sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.29.1': + resolution: {integrity: sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.29.1': + resolution: {integrity: sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==} + cpu: [x64] + os: [win32] + + '@testing-library/dom@10.4.0': + resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.6.3': + resolution: {integrity: sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/user-event@14.5.2': + resolution: {integrity: sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@vitest/expect@2.1.8': + resolution: {integrity: sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==} + + '@vitest/mocker@2.1.8': + resolution: {integrity: sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.8': + resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} + + '@vitest/runner@2.1.8': + resolution: {integrity: sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==} + + '@vitest/snapshot@2.1.8': + resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} + + '@vitest/spy@2.1.8': + resolution: {integrity: sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==} + + '@vitest/ui@2.1.8': + resolution: {integrity: sha512-5zPJ1fs0ixSVSs5+5V2XJjXLmNzjugHRyV11RqxYVR+oMcogZ9qTuSfKW+OcTV0JeFNznI83BNylzH6SSNJ1+w==} + peerDependencies: + vitest: 2.1.8 + + '@vitest/utils@2.1.8': + resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} + + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + chai@5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} + engines: {node: '>=12'} + + chalk@3.0.0: + resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} + engines: {node: '>=8'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + + cssstyle@4.1.0: + resolution: {integrity: sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==} + engines: {node: '>=18'} + + data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + es-module-lexer@1.6.0: + resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.1.0: + resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} + engines: {node: '>=12.0.0'} + + fdir@6.4.2: + resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + + flatted@3.3.2: + resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + jsdom@25.0.1: + resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + loupe@3.1.2: + resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + mrmime@2.0.0: + resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nwsapi@2.2.16: + resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==} + + parse5@7.2.1: + resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + rollup@4.29.1: + resolution: {integrity: sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rrweb-cssom@0.7.1: + resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + sirv@3.0.0: + resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==} + engines: {node: '>=18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.8.0: + resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.10: + resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} + engines: {node: '>=12.0.0'} + + tinypool@1.0.2: + resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + + tldts-core@6.1.70: + resolution: {integrity: sha512-RNnIXDB1FD4T9cpQRErEqw6ZpjLlGdMOitdV+0xtbsnwr4YFka1zpc7D4KD+aAn8oSG5JyFrdasZTE04qDE9Yg==} + + tldts@6.1.70: + resolution: {integrity: sha512-/W1YVgYVJd9ZDjey5NXadNh0mJXkiUMUue9Zebd0vpdo1sU+H4zFFTaJ1RKD4N6KFoHfcXy6l+Vu7bh+bdWCzA==} + hasBin: true + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + tough-cookie@5.0.0: + resolution: {integrity: sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==} + engines: {node: '>=16'} + + tr46@5.0.0: + resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} + engines: {node: '>=18'} + + vite-node@2.1.8: + resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.11: + resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@2.1.8: + resolution: {integrity: sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.8 + '@vitest/ui': 2.1.8 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@14.1.0: + resolution: {integrity: sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==} + engines: {node: '>=18'} + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + +snapshots: + + '@adobe/css-tools@4.4.1': {} + + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/runtime@7.26.0': + dependencies: + regenerator-runtime: 0.14.1 + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@polka/url@1.0.0-next.28': {} + + '@rollup/rollup-android-arm-eabi@4.29.1': + optional: true + + '@rollup/rollup-android-arm64@4.29.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.29.1': + optional: true + + '@rollup/rollup-darwin-x64@4.29.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.29.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.29.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.29.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.29.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.29.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.29.1': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.29.1': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.29.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.29.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.29.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.29.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.29.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.29.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.29.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.29.1': + optional: true + + '@testing-library/dom@10.4.0': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/runtime': 7.26.0 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + chalk: 4.1.2 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.6.3': + dependencies: + '@adobe/css-tools': 4.4.1 + aria-query: 5.3.2 + chalk: 3.0.0 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + lodash: 4.17.21 + redent: 3.0.0 + + '@testing-library/user-event@14.5.2(@testing-library/dom@10.4.0)': + dependencies: + '@testing-library/dom': 10.4.0 + + '@types/aria-query@5.0.4': {} + + '@types/estree@1.0.6': {} + + '@vitest/expect@2.1.8': + dependencies: + '@vitest/spy': 2.1.8 + '@vitest/utils': 2.1.8 + chai: 5.1.2 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.8(vite@5.4.11)': + dependencies: + '@vitest/spy': 2.1.8 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 5.4.11 + + '@vitest/pretty-format@2.1.8': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/runner@2.1.8': + dependencies: + '@vitest/utils': 2.1.8 + pathe: 1.1.2 + + '@vitest/snapshot@2.1.8': + dependencies: + '@vitest/pretty-format': 2.1.8 + magic-string: 0.30.17 + pathe: 1.1.2 + + '@vitest/spy@2.1.8': + dependencies: + tinyspy: 3.0.2 + + '@vitest/ui@2.1.8(vitest@2.1.8)': + dependencies: + '@vitest/utils': 2.1.8 + fflate: 0.8.2 + flatted: 3.3.2 + pathe: 1.1.2 + sirv: 3.0.0 + tinyglobby: 0.2.10 + tinyrainbow: 1.2.0 + vitest: 2.1.8(@vitest/ui@2.1.8)(jsdom@25.0.1) + + '@vitest/utils@2.1.8': + dependencies: + '@vitest/pretty-format': 2.1.8 + loupe: 3.1.2 + tinyrainbow: 1.2.0 + + agent-base@7.1.3: {} + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + + aria-query@5.3.2: {} + + assertion-error@2.0.1: {} + + asynckit@0.4.0: {} + + cac@6.7.14: {} + + chai@5.1.2: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.2 + pathval: 2.0.0 + + chalk@3.0.0: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + check-error@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + css.escape@1.5.1: {} + + cssstyle@4.1.0: + dependencies: + rrweb-cssom: 0.7.1 + + data-urls@5.0.0: + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.1.0 + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + decimal.js@10.4.3: {} + + deep-eql@5.0.2: {} + + delayed-stream@1.0.0: {} + + dequal@2.0.3: {} + + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + + entities@4.5.0: {} + + es-module-lexer@1.6.0: {} + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.6 + + expect-type@1.1.0: {} + + fdir@6.4.2(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + fflate@0.8.2: {} + + flatted@3.3.2: {} + + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + fsevents@2.3.3: + optional: true + + has-flag@4.0.0: {} + + html-encoding-sniffer@4.0.0: + dependencies: + whatwg-encoding: 3.1.1 + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + indent-string@4.0.0: {} + + is-potential-custom-element-name@1.0.1: {} + + js-tokens@4.0.0: {} + + jsdom@25.0.1: + dependencies: + cssstyle: 4.1.0 + data-urls: 5.0.0 + decimal.js: 10.4.3 + form-data: 4.0.1 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.16 + parse5: 7.2.1 + rrweb-cssom: 0.7.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 5.0.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.1.0 + ws: 8.18.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + lodash@4.17.21: {} + + loupe@3.1.2: {} + + lz-string@1.5.0: {} + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + min-indent@1.0.1: {} + + mrmime@2.0.0: {} + + ms@2.1.3: {} + + nanoid@3.3.8: {} + + nwsapi@2.2.16: {} + + parse5@7.2.1: + dependencies: + entities: 4.5.0 + + pathe@1.1.2: {} + + pathval@2.0.0: {} + + picocolors@1.1.1: {} + + picomatch@4.0.2: {} + + postcss@8.4.49: + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + punycode@2.3.1: {} + + react-is@17.0.2: {} + + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + + regenerator-runtime@0.14.1: {} + + rollup@4.29.1: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.29.1 + '@rollup/rollup-android-arm64': 4.29.1 + '@rollup/rollup-darwin-arm64': 4.29.1 + '@rollup/rollup-darwin-x64': 4.29.1 + '@rollup/rollup-freebsd-arm64': 4.29.1 + '@rollup/rollup-freebsd-x64': 4.29.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.29.1 + '@rollup/rollup-linux-arm-musleabihf': 4.29.1 + '@rollup/rollup-linux-arm64-gnu': 4.29.1 + '@rollup/rollup-linux-arm64-musl': 4.29.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.29.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.29.1 + '@rollup/rollup-linux-riscv64-gnu': 4.29.1 + '@rollup/rollup-linux-s390x-gnu': 4.29.1 + '@rollup/rollup-linux-x64-gnu': 4.29.1 + '@rollup/rollup-linux-x64-musl': 4.29.1 + '@rollup/rollup-win32-arm64-msvc': 4.29.1 + '@rollup/rollup-win32-ia32-msvc': 4.29.1 + '@rollup/rollup-win32-x64-msvc': 4.29.1 + fsevents: 2.3.3 + + rrweb-cssom@0.7.1: {} + + safer-buffer@2.1.2: {} + + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + + siginfo@2.0.0: {} + + sirv@3.0.0: + dependencies: + '@polka/url': 1.0.0-next.28 + mrmime: 2.0.0 + totalist: 3.0.1 + + source-map-js@1.2.1: {} + + stackback@0.0.2: {} + + std-env@3.8.0: {} + + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + symbol-tree@3.2.4: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.10: + dependencies: + fdir: 6.4.2(picomatch@4.0.2) + picomatch: 4.0.2 + + tinypool@1.0.2: {} + + tinyrainbow@1.2.0: {} + + tinyspy@3.0.2: {} + + tldts-core@6.1.70: {} + + tldts@6.1.70: + dependencies: + tldts-core: 6.1.70 + + totalist@3.0.1: {} + + tough-cookie@5.0.0: + dependencies: + tldts: 6.1.70 + + tr46@5.0.0: + dependencies: + punycode: 2.3.1 + + vite-node@2.1.8: + dependencies: + cac: 6.7.14 + debug: 4.4.0 + es-module-lexer: 1.6.0 + pathe: 1.1.2 + vite: 5.4.11 + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.11: + dependencies: + esbuild: 0.21.5 + postcss: 8.4.49 + rollup: 4.29.1 + optionalDependencies: + fsevents: 2.3.3 + + vitest@2.1.8(@vitest/ui@2.1.8)(jsdom@25.0.1): + dependencies: + '@vitest/expect': 2.1.8 + '@vitest/mocker': 2.1.8(vite@5.4.11) + '@vitest/pretty-format': 2.1.8 + '@vitest/runner': 2.1.8 + '@vitest/snapshot': 2.1.8 + '@vitest/spy': 2.1.8 + '@vitest/utils': 2.1.8 + chai: 5.1.2 + debug: 4.4.0 + expect-type: 1.1.0 + magic-string: 0.30.17 + pathe: 1.1.2 + std-env: 3.8.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.0.2 + tinyrainbow: 1.2.0 + vite: 5.4.11 + vite-node: 2.1.8 + why-is-node-running: 2.3.0 + optionalDependencies: + '@vitest/ui': 2.1.8(vitest@2.1.8) + jsdom: 25.0.1 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + webidl-conversions@7.0.0: {} + + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-url@14.1.0: + dependencies: + tr46: 5.0.0 + webidl-conversions: 7.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + ws@8.18.0: {} + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} From 019d0778d2a924abe90b6b6d01e7a7e14071bd76 Mon Sep 17 00:00:00 2001 From: Gyeongmin Kim Date: Sun, 5 Jan 2025 23:45:01 +0900 Subject: [PATCH 02/11] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/basic/main.basic.js | 357 +++++++++++++++++++++++++--------------- 1 file changed, 228 insertions(+), 129 deletions(-) diff --git a/src/basic/main.basic.js b/src/basic/main.basic.js index 0efffa28..5ff3c7da 100644 --- a/src/basic/main.basic.js +++ b/src/basic/main.basic.js @@ -1,204 +1,303 @@ -var prodList, sel, addBtn, cartDisp, sum, stockInfo; -var lastSel, bonusPts=0, totalAmt=0, itemCnt=0; +var productList, select, addBtn, cartDisp, sum, stockInfo; +var lastSel, + bonusPts = 0, + totalAmt = 0, + itemCnt = 0; + +productList = [ + { id: "p1", name: "상품1", val: 10000, q: 50 }, + { id: "p2", name: "상품2", val: 20000, q: 30 }, + { id: "p3", name: "상품3", val: 30000, q: 20 }, + { id: "p4", name: "상품4", val: 15000, q: 0 }, + { id: "p5", name: "상품5", val: 25000, q: 10 }, +]; + function main() { - prodList=[ - {id: 'p1', name: '상품1', val: 10000, q: 50 }, - {id: 'p2', name: '상품2', val: 20000, q: 30 }, - {id: 'p3', name: '상품3', val: 30000, q: 20 }, - {id: 'p4', name: '상품4', val: 15000, q: 0 }, - {id: 'p5', name: '상품5', val: 25000, q: 10 } - ]; - var root=document.getElementById('app'); - let cont=document.createElement('div'); - var wrap=document.createElement('div'); - let hTxt=document.createElement('h1'); - cartDisp=document.createElement('div'); - sum=document.createElement('div'); - sel=document.createElement('select'); - addBtn=document.createElement('button'); - stockInfo=document.createElement('div'); - cartDisp.id='cart-items'; - sum.id='cart-total'; - sel.id='product-select'; - addBtn.id='add-to-cart'; - stockInfo.id='stock-status'; - cont.className='bg-gray-100 p-8'; - wrap.className='max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl p-8'; - hTxt.className='text-2xl font-bold mb-4'; - sum.className='text-xl font-bold my-4'; - sel.className='border rounded p-2 mr-2'; - addBtn.className='bg-blue-500 text-white px-4 py-2 rounded'; - stockInfo.className='text-sm text-gray-500 mt-2'; - hTxt.textContent='장바구니'; - addBtn.textContent='추가'; + var root = document.getElementById("app"); + + let cont = document.createElement("div"); + cont.className = "bg-gray-100 p-8"; + + var wrap = document.createElement("div"); + wrap.className = + "max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl p-8"; + + let hTxt = document.createElement("h1"); + hTxt.className = "text-2xl font-bold mb-4"; + hTxt.textContent = "장바구니"; + + cartDisp = document.createElement("div"); + cartDisp.id = "cart-items"; + + sum = document.createElement("div"); + sum.id = "cart-total"; + sum.className = "text-xl font-bold my-4"; + + select = document.createElement("select"); + select.id = "product-select"; + select.className = "border rounded p-2 mr-2"; + + addBtn = document.createElement("button"); + addBtn.id = "add-to-cart"; + addBtn.className = "bg-blue-500 text-white px-4 py-2 rounded"; + addBtn.textContent = "추가"; + + stockInfo = document.createElement("div"); + stockInfo.id = "stock-status"; + stockInfo.className = "text-sm text-gray-500 mt-2"; + updateSelOpts(); + wrap.appendChild(hTxt); wrap.appendChild(cartDisp); wrap.appendChild(sum); - wrap.appendChild(sel); + wrap.appendChild(select); wrap.appendChild(addBtn); wrap.appendChild(stockInfo); cont.appendChild(wrap); root.appendChild(cont); + calcCart(); + setTimeout(function () { setInterval(function () { - var luckyItem=prodList[Math.floor(Math.random() * prodList.length)]; - if(Math.random() < 0.3 && luckyItem.q > 0) { - luckyItem.val=Math.round(luckyItem.val * 0.8); - alert('번개세일! ' + luckyItem.name + '이(가) 20% 할인 중입니다!'); + var luckyItem = + productList[Math.floor(Math.random() * productList.length)]; + if (Math.random() < 0.3 && luckyItem.q > 0) { + luckyItem.val = Math.round(luckyItem.val * 0.8); + alert("번개세일! " + luckyItem.name + "이(가) 20% 할인 중입니다!"); updateSelOpts(); } }, 30000); }, Math.random() * 10000); + setTimeout(function () { setInterval(function () { - if(lastSel) { - var suggest=prodList.find(function (item) { return item.id !== lastSel && item.q > 0; }); - if(suggest) { - alert(suggest.name + '은(는) 어떠세요? 지금 구매하시면 5% 추가 할인!'); - suggest.val=Math.round(suggest.val * 0.95); + if (lastSel) { + var suggest = productList.find(function (item) { + return item.id !== lastSel && item.q > 0; + }); + if (suggest) { + alert( + suggest.name + "은(는) 어떠세요? 지금 구매하시면 5% 추가 할인!" + ); + suggest.val = Math.round(suggest.val * 0.95); updateSelOpts(); } } }, 60000); }, Math.random() * 20000); -}; +} + function updateSelOpts() { - sel.innerHTML=''; - prodList.forEach(function (item) { - var opt=document.createElement('option'); - opt.value=item.id; - opt.textContent=item.name + ' - ' + item.val + '원'; - if(item.q === 0) opt.disabled=true; - sel.appendChild(opt); + select.innerHTML = ""; + productList.forEach(function (item) { + var opt = document.createElement("option"); + opt.value = item.id; + opt.textContent = item.name + " - " + item.val + "원"; + if (item.q === 0) opt.disabled = true; + select.appendChild(opt); }); } + function calcCart() { - totalAmt=0; - itemCnt=0; - var cartItems=cartDisp.children; - var subTot=0; - for (var i=0; i < cartItems.length; i++) { + totalAmt = 0; + itemCnt = 0; + + var cartItems = cartDisp.children; + var subTot = 0; + + for (var i = 0; i < cartItems.length; i++) { (function () { var curItem; - for (var j=0; j < prodList.length; j++) { - if(prodList[j].id === cartItems[i].id) { - curItem=prodList[j]; + for (var j = 0; j < productList.length; j++) { + if (productList[j].id === cartItems[i].id) { + curItem = productList[j]; break; } } - var q=parseInt(cartItems[i].querySelector('span').textContent.split('x ')[1]); - var itemTot=curItem.val * q; - var disc=0; + + var q = parseInt( + cartItems[i].querySelector("span").textContent.split("x ")[1] + ); + var itemTot = curItem.val * q; + var disc = 0; + itemCnt += q; subTot += itemTot; - if(q >= 10) { - if(curItem.id === 'p1') disc=0.1; - else if(curItem.id === 'p2') disc=0.15; - else if(curItem.id === 'p3') disc=0.2; - else if(curItem.id === 'p4') disc=0.05; - else if(curItem.id === 'p5') disc=0.25; + + if (q >= 10) { + if (curItem.id === "p1") disc = 0.1; + else if (curItem.id === "p2") disc = 0.15; + else if (curItem.id === "p3") disc = 0.2; + else if (curItem.id === "p4") disc = 0.05; + else if (curItem.id === "p5") disc = 0.25; } + totalAmt += itemTot * (1 - disc); })(); } - let discRate=0; - if(itemCnt >= 30) { - var bulkDisc=totalAmt * 0.25; - var itemDisc=subTot - totalAmt; - if(bulkDisc > itemDisc) { - totalAmt=subTot * (1 - 0.25); - discRate=0.25; + + let discRate = 0; + + if (itemCnt >= 30) { + var bulkDisc = totalAmt * 0.25; + var itemDisc = subTot - totalAmt; + + if (bulkDisc > itemDisc) { + totalAmt = subTot * (1 - 0.25); + discRate = 0.25; } else { - discRate=(subTot - totalAmt) / subTot; + discRate = (subTot - totalAmt) / subTot; } } else { - discRate=(subTot - totalAmt) / subTot; + discRate = (subTot - totalAmt) / subTot; } - if(new Date().getDay() === 2) { - totalAmt *= (1 - 0.1); - discRate=Math.max(discRate, 0.1); + + if (new Date().getDay() === 2) { + totalAmt *= 1 - 0.1; + discRate = Math.max(discRate, 0.1); } - sum.textContent='총액: ' + Math.round(totalAmt) + '원'; - if(discRate > 0) { - var span=document.createElement('span'); - span.className='text-green-500 ml-2'; - span.textContent='(' + (discRate * 100).toFixed(1) + '% 할인 적용)'; + + sum.textContent = "총액: " + Math.round(totalAmt) + "원"; + + if (discRate > 0) { + var span = document.createElement("span"); + span.className = "text-green-500 ml-2"; + span.textContent = "(" + (discRate * 100).toFixed(1) + "% 할인 적용)"; sum.appendChild(span); } + updateStockInfo(); renderBonusPts(); } -const renderBonusPts=() => { + +const renderBonusPts = () => { bonusPts = Math.floor(totalAmt / 1000); - var ptsTag=document.getElementById('loyalty-points'); - if(!ptsTag) { - ptsTag=document.createElement('span'); - ptsTag.id='loyalty-points'; - ptsTag.className='text-blue-500 ml-2'; + + var ptsTag = document.getElementById("loyalty-points"); + + if (!ptsTag) { + ptsTag = document.createElement("span"); + ptsTag.id = "loyalty-points"; + ptsTag.className = "text-blue-500 ml-2"; sum.appendChild(ptsTag); } - ptsTag.textContent='(포인트: ' + bonusPts + ')'; + + ptsTag.textContent = "(포인트: " + bonusPts + ")"; }; + function updateStockInfo() { - var infoMsg=''; - prodList.forEach(function (item) { - if(item.q < 5) {infoMsg += item.name + ': ' + (item.q > 0 ? '재고 부족 ('+item.q+'개 남음)' : '품절') + '\n'; + var infoMsg = ""; + + productList.forEach(function (item) { + if (item.q < 5) { + infoMsg += + item.name + + ": " + + (item.q > 0 ? "재고 부족 (" + item.q + "개 남음)" : "품절") + + "\n"; } }); - stockInfo.textContent=infoMsg; + + stockInfo.textContent = infoMsg; } + main(); -addBtn.addEventListener('click', function () { - var selItem=sel.value; - var itemToAdd=prodList.find(function (p) { return p.id === selItem; }); - if(itemToAdd && itemToAdd.q > 0) { - var item=document.getElementById(itemToAdd.id); - if(item) { - var newQty=parseInt(item.querySelector('span').textContent.split('x ')[1]) + 1; - if(newQty <= itemToAdd.q) { - item.querySelector('span').textContent=itemToAdd.name + ' - ' + itemToAdd.val + '원 x ' + newQty; + +addBtn.addEventListener("click", function () { + var selItem = select.value; + var itemToAdd = productList.find(function (p) { + return p.id === selItem; + }); + + if (itemToAdd && itemToAdd.q > 0) { + var item = document.getElementById(itemToAdd.id); + if (item) { + var newQty = + parseInt(item.querySelector("span").textContent.split("x ")[1]) + 1; + + if (newQty <= itemToAdd.q) { + item.querySelector("span").textContent = + itemToAdd.name + " - " + itemToAdd.val + "원 x " + newQty; itemToAdd.q--; - } else {alert('재고가 부족합니다.');} + } else { + alert("재고가 부족합니다."); + } } else { - var newItem=document.createElement('div'); - newItem.id=itemToAdd.id; - newItem.className='flex justify-between items-center mb-2'; - newItem.innerHTML='' + itemToAdd.name + ' - ' + itemToAdd.val + '원 x 1
' + - '' + - '' + - '
'; + var newItem = document.createElement("div"); + newItem.id = itemToAdd.id; + newItem.className = "flex justify-between items-center mb-2"; + newItem.innerHTML = + "" + + itemToAdd.name + + " - " + + itemToAdd.val + + "원 x 1
" + + '' + + '' + + '
'; cartDisp.appendChild(newItem); itemToAdd.q--; } + calcCart(); - lastSel=selItem; + + lastSel = selItem; } }); -cartDisp.addEventListener('click', function (event) { - var tgt=event.target; - if(tgt.classList.contains('quantity-change') || tgt.classList.contains('remove-item')) { - var prodId=tgt.dataset.productId; - var itemElem=document.getElementById(prodId); - var prod=prodList.find(function (p) { return p.id === prodId; }); - if(tgt.classList.contains('quantity-change')) { - var qtyChange=parseInt(tgt.dataset.change); - var newQty=parseInt(itemElem.querySelector('span').textContent.split('x ')[1]) + qtyChange; - if(newQty > 0 && newQty <= prod.q + parseInt(itemElem.querySelector('span').textContent.split('x ')[1])) { - itemElem.querySelector('span').textContent=itemElem.querySelector('span').textContent.split('x ')[0] + 'x ' + newQty; + +cartDisp.addEventListener("click", function (event) { + var tgt = event.target; + + if ( + tgt.classList.contains("quantity-change") || + tgt.classList.contains("remove-item") + ) { + var prodId = tgt.dataset.productId; + var itemElem = document.getElementById(prodId); + var prod = productList.find(function (p) { + return p.id === prodId; + }); + + if (tgt.classList.contains("quantity-change")) { + var qtyChange = parseInt(tgt.dataset.change); + var newQty = + parseInt(itemElem.querySelector("span").textContent.split("x ")[1]) + + qtyChange; + + if ( + newQty > 0 && + newQty <= + prod.q + + parseInt(itemElem.querySelector("span").textContent.split("x ")[1]) + ) { + itemElem.querySelector("span").textContent = + itemElem.querySelector("span").textContent.split("x ")[0] + + "x " + + newQty; prod.q -= qtyChange; - } else if(newQty <= 0) { + } else if (newQty <= 0) { itemElem.remove(); prod.q -= qtyChange; } else { - alert('재고가 부족합니다.'); + alert("재고가 부족합니다."); } - } else if(tgt.classList.contains('remove-item')) { - var remQty=parseInt(itemElem.querySelector('span').textContent.split('x ')[1]); + } else if (tgt.classList.contains("remove-item")) { + var remQty = parseInt( + itemElem.querySelector("span").textContent.split("x ")[1] + ); + prod.q += remQty; itemElem.remove(); } + calcCart(); } -}); \ No newline at end of file +}); From ffe50888436028e4d08b134e62bc6321effb77ae Mon Sep 17 00:00:00 2001 From: Gyeongmin Kim Date: Mon, 6 Jan 2025 00:08:26 +0900 Subject: [PATCH 03/11] =?UTF-8?q?refactor:=20=EA=B4=80=EC=8B=AC=EC=82=AC?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=BD=94=EB=93=9C=EB=A5=BC=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/basic/main.basic.js | 64 ++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/src/basic/main.basic.js b/src/basic/main.basic.js index 5ff3c7da..3e4793b4 100644 --- a/src/basic/main.basic.js +++ b/src/basic/main.basic.js @@ -1,10 +1,11 @@ -var productList, select, addBtn, cartDisp, sum, stockInfo; +var prodList, sel, addBtn, cartDisp, sum, stockInfo; + var lastSel, bonusPts = 0, totalAmt = 0, itemCnt = 0; -productList = [ +var prodList = [ { id: "p1", name: "상품1", val: 10000, q: 50 }, { id: "p2", name: "상품2", val: 20000, q: 30 }, { id: "p3", name: "상품3", val: 30000, q: 20 }, @@ -15,9 +16,11 @@ productList = [ function main() { var root = document.getElementById("app"); + // container let cont = document.createElement("div"); cont.className = "bg-gray-100 p-8"; + // wrapper var wrap = document.createElement("div"); wrap.className = "max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl p-8"; @@ -33,9 +36,9 @@ function main() { sum.id = "cart-total"; sum.className = "text-xl font-bold my-4"; - select = document.createElement("select"); - select.id = "product-select"; - select.className = "border rounded p-2 mr-2"; + sel = document.createElement("select"); + sel.id = "product-select"; + sel.className = "border rounded p-2 mr-2"; addBtn = document.createElement("button"); addBtn.id = "add-to-cart"; @@ -48,10 +51,11 @@ function main() { updateSelOpts(); + // wapper 안에 태그를 위치시킨다 wrap.appendChild(hTxt); wrap.appendChild(cartDisp); wrap.appendChild(sum); - wrap.appendChild(select); + wrap.appendChild(sel); wrap.appendChild(addBtn); wrap.appendChild(stockInfo); cont.appendChild(wrap); @@ -61,8 +65,7 @@ function main() { setTimeout(function () { setInterval(function () { - var luckyItem = - productList[Math.floor(Math.random() * productList.length)]; + var luckyItem = prodList[Math.floor(Math.random() * prodList.length)]; if (Math.random() < 0.3 && luckyItem.q > 0) { luckyItem.val = Math.round(luckyItem.val * 0.8); alert("번개세일! " + luckyItem.name + "이(가) 20% 할인 중입니다!"); @@ -74,7 +77,7 @@ function main() { setTimeout(function () { setInterval(function () { if (lastSel) { - var suggest = productList.find(function (item) { + var suggest = prodList.find(function (item) { return item.id !== lastSel && item.q > 0; }); if (suggest) { @@ -89,17 +92,23 @@ function main() { }, Math.random() * 20000); } +// 판매 옵션 업데이트 function updateSelOpts() { - select.innerHTML = ""; - productList.forEach(function (item) { + sel.innerHTML = ""; + prodList.forEach(function (item) { var opt = document.createElement("option"); opt.value = item.id; opt.textContent = item.name + " - " + item.val + "원"; - if (item.q === 0) opt.disabled = true; - select.appendChild(opt); + + if (item.q === 0) { + opt.disabled = true; + } + + sel.appendChild(opt); }); } +// 장바구니 function calcCart() { totalAmt = 0; itemCnt = 0; @@ -110,9 +119,9 @@ function calcCart() { for (var i = 0; i < cartItems.length; i++) { (function () { var curItem; - for (var j = 0; j < productList.length; j++) { - if (productList[j].id === cartItems[i].id) { - curItem = productList[j]; + for (var j = 0; j < prodList.length; j++) { + if (prodList[j].id === cartItems[i].id) { + curItem = prodList[j]; break; } } @@ -140,6 +149,7 @@ function calcCart() { let discRate = 0; + // 30개 이상 구매: 대량구매 25% 할인 if (itemCnt >= 30) { var bulkDisc = totalAmt * 0.25; var itemDisc = subTot - totalAmt; @@ -154,6 +164,7 @@ function calcCart() { discRate = (subTot - totalAmt) / subTot; } + // 화요일(2)이면 10% 할인 if (new Date().getDay() === 2) { totalAmt *= 1 - 0.1; discRate = Math.max(discRate, 0.1); @@ -172,25 +183,24 @@ function calcCart() { renderBonusPts(); } +// 포인트 계산 const renderBonusPts = () => { bonusPts = Math.floor(totalAmt / 1000); var ptsTag = document.getElementById("loyalty-points"); - if (!ptsTag) { ptsTag = document.createElement("span"); ptsTag.id = "loyalty-points"; ptsTag.className = "text-blue-500 ml-2"; sum.appendChild(ptsTag); } - ptsTag.textContent = "(포인트: " + bonusPts + ")"; }; +// 재고 정보 업데이트 function updateStockInfo() { var infoMsg = ""; - - productList.forEach(function (item) { + prodList.forEach(function (item) { if (item.q < 5) { infoMsg += item.name + @@ -199,20 +209,21 @@ function updateStockInfo() { "\n"; } }); - stockInfo.textContent = infoMsg; } main(); +// addBtn 클릭시 이벤트 등록 addBtn.addEventListener("click", function () { - var selItem = select.value; - var itemToAdd = productList.find(function (p) { + var selItem = sel.value; + var itemToAdd = prodList.find(function (p) { return p.id === selItem; }); if (itemToAdd && itemToAdd.q > 0) { var item = document.getElementById(itemToAdd.id); + if (item) { var newQty = parseInt(item.querySelector("span").textContent.split("x ")[1]) + 1; @@ -243,7 +254,9 @@ addBtn.addEventListener("click", function () { ''; + cartDisp.appendChild(newItem); + itemToAdd.q--; } @@ -253,16 +266,16 @@ addBtn.addEventListener("click", function () { } }); +// cartDisp 클릭시 이벤트 등록 cartDisp.addEventListener("click", function (event) { var tgt = event.target; - if ( tgt.classList.contains("quantity-change") || tgt.classList.contains("remove-item") ) { var prodId = tgt.dataset.productId; var itemElem = document.getElementById(prodId); - var prod = productList.find(function (p) { + var prod = prodList.find(function (p) { return p.id === prodId; }); @@ -293,7 +306,6 @@ cartDisp.addEventListener("click", function (event) { var remQty = parseInt( itemElem.querySelector("span").textContent.split("x ")[1] ); - prod.q += remQty; itemElem.remove(); } From abb75d46a6cad7c658c6fcced7af05fcbd12255a Mon Sep 17 00:00:00 2001 From: Gyeongmin Kim Date: Tue, 7 Jan 2025 20:31:38 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20=EC=BB=A8=EB=B2=A4=EC=85=98?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=A0=95=ED=95=9C=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=EC=A0=9D=ED=8A=B8=20=EA=B8=B0=EB=B3=B8=20=EA=B5=AC=EC=A1=B0?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=ED=8F=B4=EB=8D=94=EB=A5=BC=20?= =?UTF-8?q?=EB=A7=8C=EB=93=A0=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/basic/const/productList.js | 7 +++++++ src/basic/main.basic.js | 9 +-------- 2 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 src/basic/const/productList.js diff --git a/src/basic/const/productList.js b/src/basic/const/productList.js new file mode 100644 index 00000000..d07e313e --- /dev/null +++ b/src/basic/const/productList.js @@ -0,0 +1,7 @@ +export var prodList = [ + { id: "p1", name: "상품1", val: 10000, q: 50 }, + { id: "p2", name: "상품2", val: 20000, q: 30 }, + { id: "p3", name: "상품3", val: 30000, q: 20 }, + { id: "p4", name: "상품4", val: 15000, q: 0 }, + { id: "p5", name: "상품5", val: 25000, q: 10 }, +]; diff --git a/src/basic/main.basic.js b/src/basic/main.basic.js index 3e4793b4..445344f2 100644 --- a/src/basic/main.basic.js +++ b/src/basic/main.basic.js @@ -5,14 +5,6 @@ var lastSel, totalAmt = 0, itemCnt = 0; -var prodList = [ - { id: "p1", name: "상품1", val: 10000, q: 50 }, - { id: "p2", name: "상품2", val: 20000, q: 30 }, - { id: "p3", name: "상품3", val: 30000, q: 20 }, - { id: "p4", name: "상품4", val: 15000, q: 0 }, - { id: "p5", name: "상품5", val: 25000, q: 10 }, -]; - function main() { var root = document.getElementById("app"); @@ -63,6 +55,7 @@ function main() { calcCart(); + // 행운의 할인 이벤트 setTimeout(function () { setInterval(function () { var luckyItem = prodList[Math.floor(Math.random() * prodList.length)]; From 397c075681c7b3f390a0a882b48c9512994c4fe9 Mon Sep 17 00:00:00 2001 From: Gyeongmin Kim Date: Tue, 7 Jan 2025 22:11:03 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=EA=B3=B5=ED=86=B5=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98=EC=9C=BC=EB=A1=9C=20=EC=A0=95=ED=95=9C=20esl?= =?UTF-8?q?int=20=ED=8C=8C=EC=9D=BC=EC=9D=84=20=EC=88=98=EC=A0=95=ED=95=A9?= =?UTF-8?q?=EB=8B=88=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eslint.config.js | 42 +++++++++++++++++++++++++++++++---------- src/basic/main.basic.js | 12 +++++------- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index bb72d115..c897ee92 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,12 +1,34 @@ -import globals from "globals"; -import pluginJs from "@eslint/js"; -import pluginReact from "eslint-plugin-react"; +module.exports = { + parser: "@typescript-eslint/parser", + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:prettier/recommended", + ], + plugins: ["@typescript-eslint", "react", "react-hooks"], + rules: { + // TypeScript 관련 규칙 + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + // React 관련 규칙 + "react/react-in-jsx-scope": "off", + "react/prop-types": "off", + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", -/** @type {import('eslint').Linter.Config[]} */ -export default [ - {files: ["**/*.{js,mjs,cjs,jsx}"]}, - {languageOptions: { globals: globals.browser }}, - pluginJs.configs.recommended, - pluginReact.configs.flat.recommended, -]; \ No newline at end of file + // 일반적인 코드 스타일 + "no-console": ["warn", { allow: ["warn", "error"] }], + "prefer-const": "error", + "no-var": "error", + }, + settings: { + react: { + version: "detect", + }, + }, +}; diff --git a/src/basic/main.basic.js b/src/basic/main.basic.js index 445344f2..1b63499e 100644 --- a/src/basic/main.basic.js +++ b/src/basic/main.basic.js @@ -8,11 +8,9 @@ var lastSel, function main() { var root = document.getElementById("app"); - // container let cont = document.createElement("div"); cont.className = "bg-gray-100 p-8"; - // wrapper var wrap = document.createElement("div"); wrap.className = "max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl p-8"; @@ -43,7 +41,6 @@ function main() { updateSelOpts(); - // wapper 안에 태그를 위치시킨다 wrap.appendChild(hTxt); wrap.appendChild(cartDisp); wrap.appendChild(sum); @@ -55,11 +52,11 @@ function main() { calcCart(); - // 행운의 할인 이벤트 + // 번개세일 할인 이벤트 setTimeout(function () { setInterval(function () { var luckyItem = prodList[Math.floor(Math.random() * prodList.length)]; - if (Math.random() < 0.3 && luckyItem.q > 0) { + if (Math.random() < 0.3 && 0 < luckyItem.q) { luckyItem.val = Math.round(luckyItem.val * 0.8); alert("번개세일! " + luckyItem.name + "이(가) 20% 할인 중입니다!"); updateSelOpts(); @@ -67,11 +64,12 @@ function main() { }, 30000); }, Math.random() * 10000); + // 추천상품 할인 이베트 setTimeout(function () { setInterval(function () { if (lastSel) { var suggest = prodList.find(function (item) { - return item.id !== lastSel && item.q > 0; + return item.id !== lastSel && 0 < item.q; }); if (suggest) { alert( @@ -101,7 +99,7 @@ function updateSelOpts() { }); } -// 장바구니 +// 장바구니 계산 function calcCart() { totalAmt = 0; itemCnt = 0; From b98f5882efd7fe54e870fd79d8b5adf95ad114b1 Mon Sep 17 00:00:00 2001 From: Gyeongmin Kim Date: Tue, 7 Jan 2025 23:26:45 +0900 Subject: [PATCH 06/11] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EB=A5=BC=20=EC=88=98=EC=A0=95=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/basic/__tests__/basic.test.js | 161 +++++++++++++++++------------- 1 file changed, 94 insertions(+), 67 deletions(-) diff --git a/src/basic/__tests__/basic.test.js b/src/basic/__tests__/basic.test.js index 1afd4a58..2aa8768c 100644 --- a/src/basic/__tests__/basic.test.js +++ b/src/basic/__tests__/basic.test.js @@ -1,150 +1,175 @@ -import { beforeAll, beforeEach, afterEach, describe, expect, it, vi } from "vitest"; - -describe('basic test', () => { - +import { + beforeAll, + beforeEach, + afterEach, + describe, + expect, + it, + vi, +} from "vitest"; + +describe("basic test", () => { describe.each([ - { type: 'origin', loadFile: () => import('../../main.original.js'), }, - { type: 'basic', loadFile: () => import('../main.basic.js'), }, - ])('$type 장바구니 시나리오 테스트', ({ loadFile }) => { + { type: "origin", loadFile: () => import("../../main.original.js") }, + { type: "basic", loadFile: () => import("../main.basic.js") }, + ])("$type 장바구니 시나리오 테스트", ({ loadFile }) => { let sel, addBtn, cartDisp, sum, stockInfo; beforeAll(async () => { // DOM 초기화 - document.body.innerHTML='
'; + document.body.innerHTML = '
'; await loadFile(); // 전역 변수 참조 - sel=document.getElementById('product-select'); - addBtn=document.getElementById('add-to-cart'); - cartDisp=document.getElementById('cart-items'); - sum=document.getElementById('cart-total'); - stockInfo=document.getElementById('stock-status'); + sel = document.getElementById("product-select"); + addBtn = document.getElementById("add-to-cart"); + cartDisp = document.getElementById("cart-items"); + sum = document.getElementById("cart-total"); + stockInfo = document.getElementById("stock-status"); }); beforeEach(() => { - vi.useRealTimers() - vi.spyOn(window, 'alert').mockImplementation(() => {}); + vi.useFakeTimers(); + const mockDate = new Date("2025-1-6"); + vi.setSystemTime(mockDate); + vi.spyOn(window, "alert").mockImplementation(() => {}); }); afterEach(() => { vi.restoreAllMocks(); }); - it('초기 상태: 상품 목록이 올바르게 그려졌는지 확인', () => { + it("초기 상태: 상품 목록이 올바르게 그려졌는지 확인", () => { expect(sel).toBeDefined(); - expect(sel.tagName.toLowerCase()).toBe('select'); + expect(sel.tagName.toLowerCase()).toBe("select"); expect(sel.children.length).toBe(5); // 첫 번째 상품 확인 - expect(sel.children[0].value).toBe('p1'); - expect(sel.children[0].textContent).toBe('상품1 - 10000원'); + expect(sel.children[0].value).toBe("p1"); + expect(sel.children[0].textContent).toBe("상품1 - 10000원"); expect(sel.children[0].disabled).toBe(false); // 마지막 상품 확인 - expect(sel.children[4].value).toBe('p5'); - expect(sel.children[4].textContent).toBe('상품5 - 25000원'); + expect(sel.children[4].value).toBe("p5"); + expect(sel.children[4].textContent).toBe("상품5 - 25000원"); expect(sel.children[4].disabled).toBe(false); // 재고 없는 상품 확인 (상품4) - expect(sel.children[3].value).toBe('p4'); - expect(sel.children[3].textContent).toBe('상품4 - 15000원'); + expect(sel.children[3].value).toBe("p4"); + expect(sel.children[3].textContent).toBe("상품4 - 15000원"); expect(sel.children[3].disabled).toBe(true); }); - it('초기 상태: DOM 요소가 올바르게 생성되었는지 확인', () => { - expect(document.querySelector('h1').textContent).toBe('장바구니'); + it("초기 상태: DOM 요소가 올바르게 생성되었는지 확인", () => { + expect(document.querySelector("h1").textContent).toBe("장바구니"); expect(sel).toBeDefined(); expect(addBtn).toBeDefined(); expect(cartDisp).toBeDefined(); - expect(sum.textContent).toContain('총액: 0원(포인트: 0)'); + expect(sum.textContent).toContain("총액: 0원(포인트: 0)"); expect(stockInfo).toBeDefined(); }); - it('상품을 장바구니에 추가할 수 있는지 확인', () => { - sel.value='p1'; + it("상품을 장바구니에 추가할 수 있는지 확인", () => { + sel.value = "p1"; addBtn.click(); expect(cartDisp.children.length).toBe(1); - expect(cartDisp.children[0].querySelector('span').textContent).toContain('상품1 - 10000원 x 1'); + expect(cartDisp.children[0].querySelector("span").textContent).toContain( + "상품1 - 10000원 x 1" + ); }); - it('장바구니에서 상품 수량을 변경할 수 있는지 확인', () => { - const increaseBtn=cartDisp.querySelector('.quantity-change[data-change="1"]'); + it("장바구니에서 상품 수량을 변경할 수 있는지 확인", () => { + const increaseBtn = cartDisp.querySelector( + '.quantity-change[data-change="1"]' + ); increaseBtn.click(); - expect(cartDisp.children[0].querySelector('span').textContent).toContain('상품1 - 10000원 x 2'); + expect(cartDisp.children[0].querySelector("span").textContent).toContain( + "상품1 - 10000원 x 2" + ); }); - it('장바구니에서 상품을 삭제할 수 있는지 확인', () => { - sel.value='p1'; + it("장바구니에서 상품을 삭제할 수 있는지 확인", () => { + sel.value = "p1"; addBtn.click(); - const removeBtn=cartDisp.querySelector('.remove-item'); + const removeBtn = cartDisp.querySelector(".remove-item"); removeBtn.click(); expect(cartDisp.children.length).toBe(0); - expect(sum.textContent).toContain('총액: 0원(포인트: 0)'); + expect(sum.textContent).toContain("총액: 0원(포인트: 0)"); }); - it('총액이 올바르게 계산되는지 확인', () => { - sel.value='p1'; + it("총액이 올바르게 계산되는지 확인", () => { + sel.value = "p1"; addBtn.click(); addBtn.click(); - expect(sum.textContent).toContain('총액: 20000원(포인트: 20)'); + expect(sum.textContent).toContain("총액: 20000원(포인트: 20)"); }); - it('할인이 올바르게 적용되는지 확인', () => { - sel.value='p1'; - for (let i=0; i < 10; i++) { + it("할인이 올바르게 적용되는지 확인", () => { + sel.value = "p1"; + for (let i = 0; i < 10; i++) { addBtn.click(); } - expect(sum.textContent).toContain('(10.0% 할인 적용)'); + expect(sum.textContent).toContain("(10.0% 할인 적용)"); }); - it('포인트가 올바르게 계산되는지 확인', () => { - sel.value='p2'; + it("포인트가 올바르게 계산되는지 확인", () => { + sel.value = "p2"; addBtn.click(); - expect(document.getElementById('loyalty-points').textContent).toContain('(포인트: 128)'); + expect(document.getElementById("loyalty-points").textContent).toContain( + "(포인트: 128)" + ); }); - it('번개세일 기능이 정상적으로 동작하는지 확인', () => { + it("번개세일 기능이 정상적으로 동작하는지 확인", () => { // 일부러 랜덤이 가득한 기능을 넣어서 테스트 하기를 어렵게 만들었습니다. 이런 코드는 어떻게 하면 좋을지 한번 고민해보세요! }); - it('추천 상품 알림이 표시되는지 확인', () => { + it("추천 상품 알림이 표시되는지 확인", () => { // 일부러 랜덤이 가득한 기능을 넣어서 테스트 하기를 어렵게 만들었습니다. 이런 코드는 어떻게 하면 좋을지 한번 고민해보세요! }); - it('화요일 할인이 적용되는지 확인', () => { - const mockDate=new Date('2024-10-15'); // 화요일 - vi.useFakeTimers() + it("화요일 할인이 적용되는지 확인", () => { + const mockDate = new Date("2024-10-15"); // 화요일 + vi.useFakeTimers(); vi.setSystemTime(mockDate); - sel.value='p1'; + sel.value = "p1"; addBtn.click(); - expect(document.getElementById('cart-total').textContent).toContain('(10.0% 할인 적용)'); + expect(document.getElementById("cart-total").textContent).toContain( + "(10.0% 할인 적용)" + ); }); - it('재고가 부족한 경우 추가되지 않는지 확인', () => { + it("재고가 부족한 경우 추가되지 않는지 확인", () => { // p4 상품 선택 (재고 없음) - sel.value='p4'; + sel.value = "p4"; addBtn.click(); // p4 상품이 장바구니에 없는지 확인 - const p4InCart=Array.from(cartDisp.children).some(item => item.id === 'p4'); + const p4InCart = Array.from(cartDisp.children).some( + (item) => item.id === "p4" + ); expect(p4InCart).toBe(false); - expect(stockInfo.textContent).toContain('상품4: 품절'); + expect(stockInfo.textContent).toContain("상품4: 품절"); }); - it('재고가 부족한 경우 추가되지 않고 알림이 표시되는지 확인', () => { - sel.value='p5'; + it("재고가 부족한 경우 추가되지 않고 알림이 표시되는지 확인", () => { + sel.value = "p5"; addBtn.click(); // p5 상품이 장바구니에 추가되었는지 확인 - const p5InCart=Array.from(cartDisp.children).some(item => item.id === 'p5'); + const p5InCart = Array.from(cartDisp.children).some( + (item) => item.id === "p5" + ); expect(p5InCart).toBe(true); // 수량 증가 버튼 찾기 - const increaseBtn=cartDisp.querySelector('#p5 .quantity-change[data-change="1"]'); + const increaseBtn = cartDisp.querySelector( + '#p5 .quantity-change[data-change="1"]' + ); expect(increaseBtn).not.toBeNull(); // 수량을 10번 증가시키기 - for (let i=0; i < 10; i++) { + for (let i = 0; i < 10; i++) { increaseBtn.click(); } @@ -152,14 +177,16 @@ describe('basic test', () => { increaseBtn.click(); // 재고 부족 알림이 표시되었는지 확인 - expect(window.alert).toHaveBeenCalledWith(expect.stringContaining('재고가 부족합니다')); + expect(window.alert).toHaveBeenCalledWith( + expect.stringContaining("재고가 부족합니다") + ); // 장바구니의 상품 수량이 10개인지 확인 - const itemQuantity=cartDisp.querySelector('#p5 span').textContent; - expect(itemQuantity).toContain('x 10'); + const itemQuantity = cartDisp.querySelector("#p5 span").textContent; + expect(itemQuantity).toContain("x 10"); // 재고 상태 정보에 해당 상품이 재고 부족으로 표시되는지 확인 - expect(stockInfo.textContent).toContain('상품5: 품절'); + expect(stockInfo.textContent).toContain("상품5: 품절"); }); }); -}); \ No newline at end of file +}); From b1d9f5dbf63c7fe6bf7202ad875c711127395dfb Mon Sep 17 00:00:00 2001 From: Gyeongmin Kim Date: Tue, 7 Jan 2025 23:53:39 +0900 Subject: [PATCH 07/11] =?UTF-8?q?fix:=20=EC=95=BD=EC=96=B4=EB=A5=BC=20?= =?UTF-8?q?=EB=AA=A8=EB=91=90=20=EB=8B=A8=EC=96=B4=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/basic/const/productList.js | 10 +- src/basic/main.basic.js | 277 +++++++++++++++++---------------- 2 files changed, 146 insertions(+), 141 deletions(-) diff --git a/src/basic/const/productList.js b/src/basic/const/productList.js index d07e313e..4c33c37d 100644 --- a/src/basic/const/productList.js +++ b/src/basic/const/productList.js @@ -1,7 +1,7 @@ export var prodList = [ - { id: "p1", name: "상품1", val: 10000, q: 50 }, - { id: "p2", name: "상품2", val: 20000, q: 30 }, - { id: "p3", name: "상품3", val: 30000, q: 20 }, - { id: "p4", name: "상품4", val: 15000, q: 0 }, - { id: "p5", name: "상품5", val: 25000, q: 10 }, + { id: "p1", name: "상품1", value: 10000, quantity: 50 }, + { id: "p2", name: "상품2", value: 20000, quantity: 30 }, + { id: "p3", name: "상품3", value: 30000, quantity: 20 }, + { id: "p4", name: "상품4", value: 15000, quantity: 0 }, + { id: "p5", name: "상품5", value: 25000, quantity: 10 }, ]; diff --git a/src/basic/main.basic.js b/src/basic/main.basic.js index 1b63499e..021bb9da 100644 --- a/src/basic/main.basic.js +++ b/src/basic/main.basic.js @@ -1,9 +1,9 @@ -var prodList, sel, addBtn, cartDisp, sum, stockInfo; +var productList, select, addButton, cartDisplay, sum, stockInfo; -var lastSel, - bonusPts = 0, - totalAmt = 0, - itemCnt = 0; +var lastSell, + bonusPoints = 0, + totalAmount = 0, + itemCounts = 0; function main() { var root = document.getElementById("app"); @@ -15,37 +15,37 @@ function main() { wrap.className = "max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl p-8"; - let hTxt = document.createElement("h1"); - hTxt.className = "text-2xl font-bold mb-4"; - hTxt.textContent = "장바구니"; + let hText = document.createElement("h1"); + hText.className = "text-2xl font-bold mb-4"; + hText.textContent = "장바구니"; - cartDisp = document.createElement("div"); - cartDisp.id = "cart-items"; + cartDisplay = document.createElement("div"); + cartDisplay.id = "cart-items"; sum = document.createElement("div"); sum.id = "cart-total"; sum.className = "text-xl font-bold my-4"; - sel = document.createElement("select"); - sel.id = "product-select"; - sel.className = "border rounded p-2 mr-2"; + select = document.createElement("select"); + select.id = "product-select"; + select.className = "border rounded p-2 mr-2"; - addBtn = document.createElement("button"); - addBtn.id = "add-to-cart"; - addBtn.className = "bg-blue-500 text-white px-4 py-2 rounded"; - addBtn.textContent = "추가"; + addButton = document.createElement("button"); + addButton.id = "add-to-cart"; + addButton.className = "bg-blue-500 text-white px-4 py-2 rounded"; + addButton.textContent = "추가"; stockInfo = document.createElement("div"); stockInfo.id = "stock-status"; stockInfo.className = "text-sm text-gray-500 mt-2"; - updateSelOpts(); + updateSelectOptions(); - wrap.appendChild(hTxt); - wrap.appendChild(cartDisp); + wrap.appendChild(hText); + wrap.appendChild(cartDisplay); wrap.appendChild(sum); - wrap.appendChild(sel); - wrap.appendChild(addBtn); + wrap.appendChild(select); + wrap.appendChild(addButton); wrap.appendChild(stockInfo); cont.appendChild(wrap); root.appendChild(cont); @@ -55,11 +55,12 @@ function main() { // 번개세일 할인 이벤트 setTimeout(function () { setInterval(function () { - var luckyItem = prodList[Math.floor(Math.random() * prodList.length)]; - if (Math.random() < 0.3 && 0 < luckyItem.q) { - luckyItem.val = Math.round(luckyItem.val * 0.8); + var luckyItem = + productList[Math.floor(Math.random() * productList.length)]; + if (Math.random() < 0.3 && 0 < luckyItem.quantity) { + luckyItem.value = Math.round(luckyItem.value * 0.8); alert("번개세일! " + luckyItem.name + "이(가) 20% 할인 중입니다!"); - updateSelOpts(); + updateSelectOptions(); } }, 30000); }, Math.random() * 10000); @@ -67,106 +68,106 @@ function main() { // 추천상품 할인 이베트 setTimeout(function () { setInterval(function () { - if (lastSel) { - var suggest = prodList.find(function (item) { - return item.id !== lastSel && 0 < item.q; + if (lastSell) { + var suggest = productList.find(function (item) { + return item.id !== lastSell && 0 < item.quantity; }); if (suggest) { alert( suggest.name + "은(는) 어떠세요? 지금 구매하시면 5% 추가 할인!" ); - suggest.val = Math.round(suggest.val * 0.95); - updateSelOpts(); + suggest.value = Math.round(suggest.value * 0.95); + updateSelectOptions(); } } }, 60000); }, Math.random() * 20000); } -// 판매 옵션 업데이트 -function updateSelOpts() { - sel.innerHTML = ""; - prodList.forEach(function (item) { - var opt = document.createElement("option"); - opt.value = item.id; - opt.textContent = item.name + " - " + item.val + "원"; +// 상품 업데이트 +function updateSelectOptions() { + select.innerHTML = ""; + productList.forEach(function (item) { + var option = document.createElement("option"); + option.value = item.id; + option.textContent = item.name + " - " + item.value + "원"; - if (item.q === 0) { - opt.disabled = true; + if (item.quantity === 0) { + option.disabled = true; } - sel.appendChild(opt); + select.appendChild(option); }); } // 장바구니 계산 function calcCart() { - totalAmt = 0; - itemCnt = 0; + totalAmount = 0; + itemCounts = 0; - var cartItems = cartDisp.children; - var subTot = 0; + var cartItems = cartDisplay.children; + var subTotal = 0; for (var i = 0; i < cartItems.length; i++) { (function () { - var curItem; - for (var j = 0; j < prodList.length; j++) { - if (prodList[j].id === cartItems[i].id) { - curItem = prodList[j]; + var currentItem; + for (var j = 0; j < productList.length; j++) { + if (productList[j].id === cartItems[i].id) { + currentItem = productList[j]; break; } } - var q = parseInt( + var quantity = parseInt( cartItems[i].querySelector("span").textContent.split("x ")[1] ); - var itemTot = curItem.val * q; - var disc = 0; - - itemCnt += q; - subTot += itemTot; - - if (q >= 10) { - if (curItem.id === "p1") disc = 0.1; - else if (curItem.id === "p2") disc = 0.15; - else if (curItem.id === "p3") disc = 0.2; - else if (curItem.id === "p4") disc = 0.05; - else if (curItem.id === "p5") disc = 0.25; + var itemTotal = currentItem.value * quantity; + var discount = 0; + + itemCounts += quantity; + subTotal += itemTotal; + + if (quantity >= 10) { + if (currentItem.id === "p1") discount = 0.1; + else if (currentItem.id === "p2") discount = 0.15; + else if (currentItem.id === "p3") discount = 0.2; + else if (currentItem.id === "p4") discount = 0.05; + else if (currentItem.id === "p5") discount = 0.25; } - totalAmt += itemTot * (1 - disc); + totalAmount += itemTotal * (1 - discount); })(); } - let discRate = 0; + let discountRate = 0; // 30개 이상 구매: 대량구매 25% 할인 - if (itemCnt >= 30) { - var bulkDisc = totalAmt * 0.25; - var itemDisc = subTot - totalAmt; + if (itemCounts >= 30) { + var bulkDiscount = totalAmount * 0.25; + var itemDiscount = subTotal - totalAmount; - if (bulkDisc > itemDisc) { - totalAmt = subTot * (1 - 0.25); - discRate = 0.25; + if (bulkDiscount > itemDiscount) { + totalAmount = subTotal * (1 - 0.25); + discountRate = 0.25; } else { - discRate = (subTot - totalAmt) / subTot; + discountRate = (subTotal - totalAmount) / subTotal; } } else { - discRate = (subTot - totalAmt) / subTot; + discountRate = (subTotal - totalAmount) / subTotal; } // 화요일(2)이면 10% 할인 if (new Date().getDay() === 2) { - totalAmt *= 1 - 0.1; - discRate = Math.max(discRate, 0.1); + totalAmount *= 1 - 0.1; + discountRate = Math.max(discountRate, 0.1); } - sum.textContent = "총액: " + Math.round(totalAmt) + "원"; + sum.textContent = "총액: " + Math.round(totalAmount) + "원"; - if (discRate > 0) { + if (discountRate > 0) { var span = document.createElement("span"); span.className = "text-green-500 ml-2"; - span.textContent = "(" + (discRate * 100).toFixed(1) + "% 할인 적용)"; + span.textContent = "(" + (discountRate * 100).toFixed(1) + "% 할인 적용)"; sum.appendChild(span); } @@ -176,53 +177,55 @@ function calcCart() { // 포인트 계산 const renderBonusPts = () => { - bonusPts = Math.floor(totalAmt / 1000); - - var ptsTag = document.getElementById("loyalty-points"); - if (!ptsTag) { - ptsTag = document.createElement("span"); - ptsTag.id = "loyalty-points"; - ptsTag.className = "text-blue-500 ml-2"; - sum.appendChild(ptsTag); + bonusPoints = Math.floor(totalAmount / 1000); + + var pointsTag = document.getElementById("loyalty-points"); + if (!pointsTag) { + pointsTag = document.createElement("span"); + pointsTag.id = "loyalty-points"; + pointsTag.className = "text-blue-500 ml-2"; + sum.appendChild(pointsTag); } - ptsTag.textContent = "(포인트: " + bonusPts + ")"; + pointsTag.textContent = "(포인트: " + bonusPoints + ")"; }; // 재고 정보 업데이트 function updateStockInfo() { - var infoMsg = ""; - prodList.forEach(function (item) { - if (item.q < 5) { - infoMsg += + var infoMessage = ""; + productList.forEach(function (item) { + if (item.quantity < 5) { + infoMessage += item.name + ": " + - (item.q > 0 ? "재고 부족 (" + item.q + "개 남음)" : "품절") + + (item.quantity > 0 + ? "재고 부족 (" + item.quantity + "개 남음)" + : "품절") + "\n"; } }); - stockInfo.textContent = infoMsg; + stockInfo.textContent = infoMessage; } main(); -// addBtn 클릭시 이벤트 등록 -addBtn.addEventListener("click", function () { - var selItem = sel.value; - var itemToAdd = prodList.find(function (p) { - return p.id === selItem; +// addButton 클릭시 이벤트 등록 +addButton.addEventListener("click", function () { + var selectedItem = select.value; + var itemToAdd = productList.find(function (p) { + return p.id === selectedItem; }); - if (itemToAdd && itemToAdd.q > 0) { + if (itemToAdd && itemToAdd.quantity > 0) { var item = document.getElementById(itemToAdd.id); if (item) { - var newQty = + var newQuantity = parseInt(item.querySelector("span").textContent.split("x ")[1]) + 1; - if (newQty <= itemToAdd.q) { + if (newQuantity <= itemToAdd.quantity) { item.querySelector("span").textContent = - itemToAdd.name + " - " + itemToAdd.val + "원 x " + newQty; - itemToAdd.q--; + itemToAdd.name + " - " + itemToAdd.value + "원 x " + newQuantity; + itemToAdd.quantity--; } else { alert("재고가 부족합니다."); } @@ -234,7 +237,7 @@ addBtn.addEventListener("click", function () { "" + itemToAdd.name + " - " + - itemToAdd.val + + itemToAdd.value + "원 x 1
" + '
'; - cartDisp.appendChild(newItem); + cartDisplay.appendChild(newItem); - itemToAdd.q--; + itemToAdd.quantity--; } calcCart(); - lastSel = selItem; + lastSell = selItem; } }); -// cartDisp 클릭시 이벤트 등록 -cartDisp.addEventListener("click", function (event) { - var tgt = event.target; +// cartDisplay 클릭시 이벤트 등록 +cartDisplay.addEventListener("click", function (event) { + var target = event.target; if ( - tgt.classList.contains("quantity-change") || - tgt.classList.contains("remove-item") + target.classList.contains("quantity-change") || + target.classList.contains("remove-item") ) { - var prodId = tgt.dataset.productId; - var itemElem = document.getElementById(prodId); - var prod = prodList.find(function (p) { - return p.id === prodId; + var productId = target.dataset.productId; + var itemElement = document.getElementById(productId); + var product = productList.find(function (p) { + return p.id === productId; }); - if (tgt.classList.contains("quantity-change")) { - var qtyChange = parseInt(tgt.dataset.change); - var newQty = - parseInt(itemElem.querySelector("span").textContent.split("x ")[1]) + - qtyChange; + if (target.classList.contains("quantity-change")) { + var quantityChange = parseInt(target.dataset.change); + var newQuantity = + parseInt(itemElement.querySelector("span").textContent.split("x ")[1]) + + quantityChange; if ( - newQty > 0 && - newQty <= - prod.q + - parseInt(itemElem.querySelector("span").textContent.split("x ")[1]) + newQuantity > 0 && + newQuantity <= + product.quantity + + parseInt( + itemElement.querySelector("span").textContent.split("x ")[1] + ) ) { - itemElem.querySelector("span").textContent = - itemElem.querySelector("span").textContent.split("x ")[0] + + itemElement.querySelector("span").textContent = + itemElement.querySelector("span").textContent.split("x ")[0] + "x " + - newQty; - prod.q -= qtyChange; - } else if (newQty <= 0) { - itemElem.remove(); - prod.q -= qtyChange; + newQuantity; + product.quantity -= quantityChange; + } else if (newQuantity <= 0) { + itemElement.remove(); + product.quantity -= quantityChange; } else { alert("재고가 부족합니다."); } - } else if (tgt.classList.contains("remove-item")) { - var remQty = parseInt( - itemElem.querySelector("span").textContent.split("x ")[1] + } else if (target.classList.contains("remove-item")) { + var removeQuantity = parseInt( + itemElement.querySelector("span").textContent.split("x ")[1] ); - prod.q += remQty; - itemElem.remove(); + product.quantity += removeQuantity; + itemElement.remove(); } calcCart(); From fcd6d04a00fabbee620590296b97bc943fcd72a9 Mon Sep 17 00:00:00 2001 From: Gyeongmin Kim Date: Wed, 8 Jan 2025 21:24:01 +0900 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20prettier=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .prettierrc | 18 + package.json | 10 +- pnpm-lock.yaml | 65 ++++ yarn.lock | 1004 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1096 insertions(+), 1 deletion(-) create mode 100644 .prettierrc create mode 100644 yarn.lock diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..0d718e23 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,18 @@ +{ + "printWidth": 100, + "useTabs": false, + "tabWidth": 2, + "semi": true, + "singleQuote": true, + "trailingComma": "es5", + "arrowParens": "always", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "jsxSingleQuote": false, + "proseWrap": "preserve", + "htmlWhitespaceSensitivity": "css", + "endOfLine": "lf", + "requirePragma": false, + "insertPragma": false, + "embeddedLanguageFormatting": "auto" +} diff --git a/package.json b/package.json index b48a6df6..358cd8f9 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,12 @@ "devDependencies": { "@testing-library/jest-dom": "^6.5.0", "@testing-library/user-event": "^14.5.2", + "@types/react": "^19.0.3", + "@types/react-dom": "^19.0.2", "@vitest/ui": "^2.1.1", "jsdom": "^25.0.0", + "prettier": "^3.4.2", + "typescript": "^5.7.2", "vite": "^5.1.0", "vitest": "^2.1.1" }, @@ -26,5 +30,9 @@ "main": "eslint.config.js", "keywords": [], "author": "", - "license": "ISC" + "license": "ISC", + "dependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8ffc0941..41052efc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,13 @@ settings: importers: .: + dependencies: + react: + specifier: ^19.0.0 + version: 19.0.0 + react-dom: + specifier: ^19.0.0 + version: 19.0.0(react@19.0.0) devDependencies: '@testing-library/jest-dom': specifier: ^6.5.0 @@ -14,12 +21,21 @@ importers: '@testing-library/user-event': specifier: ^14.5.2 version: 14.5.2(@testing-library/dom@10.4.0) + '@types/react': + specifier: ^19.0.3 + version: 19.0.3 + '@types/react-dom': + specifier: ^19.0.2 + version: 19.0.2(@types/react@19.0.3) '@vitest/ui': specifier: ^2.1.1 version: 2.1.8(vitest@2.1.8) jsdom: specifier: ^25.0.0 version: 25.0.1 + typescript: + specifier: ^5.7.2 + version: 5.7.2 vite: specifier: ^5.1.0 version: 5.4.11 @@ -303,6 +319,14 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/react-dom@19.0.2': + resolution: {integrity: sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==} + peerDependencies: + '@types/react': ^19.0.0 + + '@types/react@19.0.3': + resolution: {integrity: sha512-UavfHguIjnnuq9O67uXfgy/h3SRJbidAYvNjLceB+2RIKVRBzVsh0QO+Pw6BCSQqFS9xwzKfwstXx0m6AbAREA==} + '@vitest/expect@2.1.8': resolution: {integrity: sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==} @@ -405,6 +429,9 @@ packages: resolution: {integrity: sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==} engines: {node: '>=18'} + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + data-urls@5.0.0: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} @@ -589,9 +616,18 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + react-dom@19.0.0: + resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} + peerDependencies: + react: ^19.0.0 + react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react@19.0.0: + resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} + engines: {node: '>=0.10.0'} + redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -614,6 +650,9 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} + scheduler@0.25.0: + resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -683,6 +722,11 @@ packages: resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} engines: {node: '>=18'} + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + vite-node@2.1.8: resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} engines: {node: ^18.0.0 || >=20.0.0} @@ -963,6 +1007,14 @@ snapshots: '@types/estree@1.0.6': {} + '@types/react-dom@19.0.2(@types/react@19.0.3)': + dependencies: + '@types/react': 19.0.3 + + '@types/react@19.0.3': + dependencies: + csstype: 3.1.3 + '@vitest/expect@2.1.8': dependencies: '@vitest/spy': 2.1.8 @@ -1072,6 +1124,8 @@ snapshots: dependencies: rrweb-cssom: 0.7.1 + csstype@3.1.3: {} + data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 @@ -1256,8 +1310,15 @@ snapshots: punycode@2.3.1: {} + react-dom@19.0.0(react@19.0.0): + dependencies: + react: 19.0.0 + scheduler: 0.25.0 + react-is@17.0.2: {} + react@19.0.0: {} + redent@3.0.0: dependencies: indent-string: 4.0.0 @@ -1298,6 +1359,8 @@ snapshots: dependencies: xmlchars: 2.2.0 + scheduler@0.25.0: {} + siginfo@2.0.0: {} sirv@3.0.0: @@ -1353,6 +1416,8 @@ snapshots: dependencies: punycode: 2.3.1 + typescript@5.7.2: {} + vite-node@2.1.8: dependencies: cac: 6.7.14 diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..47c66839 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1004 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@adobe/css-tools@^4.4.0": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.1.tgz#2447a230bfe072c1659e6815129c03cf170710e3" + integrity sha512-12WGKBQzjUAI4ayyF4IAtfw2QR/IDoqk6jTddXDhtYTJF9ASmoE1zst7cVtP0aL/F1jUJL5r+JxKXKEgHNbEUQ== + +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + +"@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@polka/url@^1.0.0-next.24": + version "1.0.0-next.28" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.28.tgz#d45e01c4a56f143ee69c54dd6b12eade9e270a73" + integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw== + +"@rollup/rollup-android-arm-eabi@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz#14c737dc19603a096568044eadaa60395eefb809" + integrity sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q== + +"@rollup/rollup-android-arm64@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz#9d81ea54fc5650eb4ebbc0a7d84cee331bfa30ad" + integrity sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w== + +"@rollup/rollup-darwin-arm64@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz#29448cb1370cf678b50743d2e392be18470abc23" + integrity sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q== + +"@rollup/rollup-darwin-x64@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz#0ca99741c3ed096700557a43bb03359450c7857d" + integrity sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA== + +"@rollup/rollup-freebsd-arm64@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz#233f8e4c2f54ad9b719cd9645887dcbd12b38003" + integrity sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ== + +"@rollup/rollup-freebsd-x64@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz#dfba762a023063dc901610722995286df4a48360" + integrity sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw== + +"@rollup/rollup-linux-arm-gnueabihf@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz#b9da54171726266c5ef4237f462a85b3c3cf6ac9" + integrity sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg== + +"@rollup/rollup-linux-arm-musleabihf@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz#b9db69b3f85f5529eb992936d8f411ee6d04297b" + integrity sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug== + +"@rollup/rollup-linux-arm64-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz#2550cf9bb4d47d917fd1ab4af756d7bbc3ee1528" + integrity sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw== + +"@rollup/rollup-linux-arm64-musl@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz#9d06b26d286c7dded6336961a2f83e48330e0c80" + integrity sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA== + +"@rollup/rollup-linux-loongarch64-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz#e957bb8fee0c8021329a34ca8dfa825826ee0e2e" + integrity sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ== + +"@rollup/rollup-linux-powerpc64le-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz#e8585075ddfb389222c5aada39ea62d6d2511ccc" + integrity sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw== + +"@rollup/rollup-linux-riscv64-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz#7d0d40cee7946ccaa5a4e19a35c6925444696a9e" + integrity sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw== + +"@rollup/rollup-linux-s390x-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz#c2dcd8a4b08b2f2778eceb7a5a5dfde6240ebdea" + integrity sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA== + +"@rollup/rollup-linux-x64-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz#183637d91456877cb83d0a0315eb4788573aa588" + integrity sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg== + +"@rollup/rollup-linux-x64-musl@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz#036a4c860662519f1f9453807547fd2a11d5bb01" + integrity sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow== + +"@rollup/rollup-win32-arm64-msvc@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz#51cad812456e616bfe4db5238fb9c7497e042a52" + integrity sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw== + +"@rollup/rollup-win32-ia32-msvc@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz#661c8b3e4cd60f51deaa39d153aac4566e748e5e" + integrity sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw== + +"@rollup/rollup-win32-x64-msvc@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz#73bf1885ff052b82fbb0f82f8671f73c36e9137c" + integrity sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og== + +"@testing-library/jest-dom@^6.5.0": + version "6.6.3" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz#26ba906cf928c0f8172e182c6fe214eb4f9f2bd2" + integrity sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA== + dependencies: + "@adobe/css-tools" "^4.4.0" + aria-query "^5.0.0" + chalk "^3.0.0" + css.escape "^1.5.1" + dom-accessibility-api "^0.6.3" + lodash "^4.17.21" + redent "^3.0.0" + +"@testing-library/user-event@^14.5.2": + version "14.5.2" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.2.tgz#db7257d727c891905947bd1c1a99da20e03c2ebd" + integrity sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ== + +"@types/estree@1.0.6", "@types/estree@^1.0.0": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/react-dom@^19.0.2": + version "19.0.2" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.2.tgz#ad21f9a1ee881817995fd3f7fd33659c87e7b1b7" + integrity sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg== + +"@types/react@^19.0.3": + version "19.0.3" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.3.tgz#7867240defc1a3686f151644ac886a7e8e0868f4" + integrity sha512-UavfHguIjnnuq9O67uXfgy/h3SRJbidAYvNjLceB+2RIKVRBzVsh0QO+Pw6BCSQqFS9xwzKfwstXx0m6AbAREA== + dependencies: + csstype "^3.0.2" + +"@vitest/expect@2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-2.1.8.tgz#13fad0e8d5a0bf0feb675dcf1d1f1a36a1773bc1" + integrity sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw== + dependencies: + "@vitest/spy" "2.1.8" + "@vitest/utils" "2.1.8" + chai "^5.1.2" + tinyrainbow "^1.2.0" + +"@vitest/mocker@2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-2.1.8.tgz#51dec42ac244e949d20009249e033e274e323f73" + integrity sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA== + dependencies: + "@vitest/spy" "2.1.8" + estree-walker "^3.0.3" + magic-string "^0.30.12" + +"@vitest/pretty-format@2.1.8", "@vitest/pretty-format@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-2.1.8.tgz#88f47726e5d0cf4ba873d50c135b02e4395e2bca" + integrity sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ== + dependencies: + tinyrainbow "^1.2.0" + +"@vitest/runner@2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-2.1.8.tgz#b0e2dd29ca49c25e9323ea2a45a5125d8729759f" + integrity sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg== + dependencies: + "@vitest/utils" "2.1.8" + pathe "^1.1.2" + +"@vitest/snapshot@2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-2.1.8.tgz#d5dc204f4b95dc8b5e468b455dfc99000047d2de" + integrity sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg== + dependencies: + "@vitest/pretty-format" "2.1.8" + magic-string "^0.30.12" + pathe "^1.1.2" + +"@vitest/spy@2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-2.1.8.tgz#bc41af3e1e6a41ae3b67e51f09724136b88fa447" + integrity sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg== + dependencies: + tinyspy "^3.0.2" + +"@vitest/ui@^2.1.1": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-2.1.8.tgz#4a4d88e20bcced4c8710826cd4e2795f5ec1f0a1" + integrity sha512-5zPJ1fs0ixSVSs5+5V2XJjXLmNzjugHRyV11RqxYVR+oMcogZ9qTuSfKW+OcTV0JeFNznI83BNylzH6SSNJ1+w== + dependencies: + "@vitest/utils" "2.1.8" + fflate "^0.8.2" + flatted "^3.3.1" + pathe "^1.1.2" + sirv "^3.0.0" + tinyglobby "^0.2.10" + tinyrainbow "^1.2.0" + +"@vitest/utils@2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.1.8.tgz#f8ef85525f3362ebd37fd25d268745108d6ae388" + integrity sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA== + dependencies: + "@vitest/pretty-format" "2.1.8" + loupe "^3.1.2" + tinyrainbow "^1.2.0" + +agent-base@^7.1.0, agent-base@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" + integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +aria-query@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" + integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== + +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + +chai@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.1.2.tgz#3afbc340b994ae3610ca519a6c70ace77ad4378d" + integrity sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw== + dependencies: + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-error@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" + integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +css.escape@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== + +cssstyle@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-4.1.0.tgz#161faee382af1bafadb6d3867a92a19bcb4aea70" + integrity sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA== + dependencies: + rrweb-cssom "^0.7.1" + +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +data-urls@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde" + integrity sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg== + dependencies: + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + +debug@4, debug@^4.3.4, debug@^4.3.7: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + +decimal.js@^10.4.3: + version "10.4.3" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +dom-accessibility-api@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz#993e925cc1d73f2c662e7d75dd5a5445259a8fd8" + integrity sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w== + +entities@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +es-module-lexer@^1.5.4: + version "1.6.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.6.0.tgz#da49f587fd9e68ee2404fe4e256c0c7d3a81be21" + integrity sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ== + +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +expect-type@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.1.0.tgz#a146e414250d13dfc49eafcfd1344a4060fa4c75" + integrity sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA== + +fdir@^6.4.2: + version "6.4.2" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.2.tgz#ddaa7ce1831b161bc3657bb99cb36e1622702689" + integrity sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ== + +fflate@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea" + integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A== + +flatted@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + +form-data@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +html-encoding-sniffer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" + integrity sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ== + dependencies: + whatwg-encoding "^3.1.1" + +http-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + +https-proxy-agent@^7.0.5: + version "7.0.6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== + dependencies: + agent-base "^7.1.2" + debug "4" + +iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +jsdom@^25.0.0: + version "25.0.1" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-25.0.1.tgz#536ec685c288fc8a5773a65f82d8b44badcc73ef" + integrity sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw== + dependencies: + cssstyle "^4.1.0" + data-urls "^5.0.0" + decimal.js "^10.4.3" + form-data "^4.0.0" + html-encoding-sniffer "^4.0.0" + http-proxy-agent "^7.0.2" + https-proxy-agent "^7.0.5" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.12" + parse5 "^7.1.2" + rrweb-cssom "^0.7.1" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^5.0.0" + w3c-xmlserializer "^5.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^3.1.1" + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + ws "^8.18.0" + xml-name-validator "^5.0.0" + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loupe@^3.1.0, loupe@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.2.tgz#c86e0696804a02218f2206124c45d8b15291a240" + integrity sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg== + +magic-string@^0.30.12: + version "0.30.17" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +mrmime@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" + integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@^3.3.7: + version "3.3.8" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" + integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== + +nwsapi@^2.2.12: + version "2.2.16" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.16.tgz#177760bba02c351df1d2644e220c31dfec8cdb43" + integrity sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ== + +parse5@^7.1.2: + version "7.2.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.1.tgz#8928f55915e6125f430cc44309765bf17556a33a" + integrity sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ== + dependencies: + entities "^4.5.0" + +pathe@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" + integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== + +pathval@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" + integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + +postcss@^8.4.43: + version "8.4.49" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19" + integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== + dependencies: + nanoid "^3.3.7" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +prettier@^3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f" + integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ== + +punycode@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +react-dom@^19.0.0: + version "19.0.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57" + integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ== + dependencies: + scheduler "^0.25.0" + +react@^19.0.0: + version "19.0.0" + resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd" + integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ== + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + +rollup@^4.20.0: + version "4.30.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.30.1.tgz#d5c3d066055259366cdc3eb6f1d051c5d6afaf74" + integrity sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w== + dependencies: + "@types/estree" "1.0.6" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.30.1" + "@rollup/rollup-android-arm64" "4.30.1" + "@rollup/rollup-darwin-arm64" "4.30.1" + "@rollup/rollup-darwin-x64" "4.30.1" + "@rollup/rollup-freebsd-arm64" "4.30.1" + "@rollup/rollup-freebsd-x64" "4.30.1" + "@rollup/rollup-linux-arm-gnueabihf" "4.30.1" + "@rollup/rollup-linux-arm-musleabihf" "4.30.1" + "@rollup/rollup-linux-arm64-gnu" "4.30.1" + "@rollup/rollup-linux-arm64-musl" "4.30.1" + "@rollup/rollup-linux-loongarch64-gnu" "4.30.1" + "@rollup/rollup-linux-powerpc64le-gnu" "4.30.1" + "@rollup/rollup-linux-riscv64-gnu" "4.30.1" + "@rollup/rollup-linux-s390x-gnu" "4.30.1" + "@rollup/rollup-linux-x64-gnu" "4.30.1" + "@rollup/rollup-linux-x64-musl" "4.30.1" + "@rollup/rollup-win32-arm64-msvc" "4.30.1" + "@rollup/rollup-win32-ia32-msvc" "4.30.1" + "@rollup/rollup-win32-x64-msvc" "4.30.1" + fsevents "~2.3.2" + +rrweb-cssom@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz#c73451a484b86dd7cfb1e0b2898df4b703183e4b" + integrity sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg== + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + +scheduler@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015" + integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA== + +siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + +sirv@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-3.0.0.tgz#f8d90fc528f65dff04cb597a88609d4e8a4361ce" + integrity sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg== + dependencies: + "@polka/url" "^1.0.0-next.24" + mrmime "^2.0.0" + totalist "^3.0.0" + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +stackback@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== + +std-env@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.8.0.tgz#b56ffc1baf1a29dcc80a3bdf11d7fca7c315e7d5" + integrity sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w== + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +tinybench@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" + integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== + +tinyexec@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + +tinyglobby@^0.2.10: + version "0.2.10" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.10.tgz#e712cf2dc9b95a1f5c5bbd159720e15833977a0f" + integrity sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew== + dependencies: + fdir "^6.4.2" + picomatch "^4.0.2" + +tinypool@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.0.2.tgz#706193cc532f4c100f66aa00b01c42173d9051b2" + integrity sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA== + +tinyrainbow@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-1.2.0.tgz#5c57d2fc0fb3d1afd78465c33ca885d04f02abb5" + integrity sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ== + +tinyspy@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" + integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== + +tldts-core@^6.1.71: + version "6.1.71" + resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-6.1.71.tgz#04069cbdcf75b7fcb68fb4c1e00591cd3a2d4a5c" + integrity sha512-LRbChn2YRpic1KxY+ldL1pGXN/oVvKfCVufwfVzEQdFYNo39uF7AJa/WXdo+gYO7PTvdfkCPCed6Hkvz/kR7jg== + +tldts@^6.1.32: + version "6.1.71" + resolved "https://registry.yarnpkg.com/tldts/-/tldts-6.1.71.tgz#e0db0853dd533628729d6a97a211450205fa21e4" + integrity sha512-LQIHmHnuzfZgZWAf2HzL83TIIrD8NhhI0DVxqo9/FdOd4ilec+NTNZOlDZf7EwrTNoutccbsHjvWHYXLAtvxjw== + dependencies: + tldts-core "^6.1.71" + +totalist@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" + integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== + +tough-cookie@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-5.0.0.tgz#6b6518e2b5c070cf742d872ee0f4f92d69eac1af" + integrity sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q== + dependencies: + tldts "^6.1.32" + +tr46@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.0.0.tgz#3b46d583613ec7283020d79019f1335723801cec" + integrity sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g== + dependencies: + punycode "^2.3.1" + +typescript@^5.7.2: + version "5.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6" + integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg== + +vite-node@2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-2.1.8.tgz#9495ca17652f6f7f95ca7c4b568a235e0c8dbac5" + integrity sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg== + dependencies: + cac "^6.7.14" + debug "^4.3.7" + es-module-lexer "^1.5.4" + pathe "^1.1.2" + vite "^5.0.0" + +vite@^5.0.0, vite@^5.1.0: + version "5.4.11" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.11.tgz#3b415cd4aed781a356c1de5a9ebafb837715f6e5" + integrity sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.43" + rollup "^4.20.0" + optionalDependencies: + fsevents "~2.3.3" + +vitest@^2.1.1: + version "2.1.8" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-2.1.8.tgz#2e6a00bc24833574d535c96d6602fb64163092fa" + integrity sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ== + dependencies: + "@vitest/expect" "2.1.8" + "@vitest/mocker" "2.1.8" + "@vitest/pretty-format" "^2.1.8" + "@vitest/runner" "2.1.8" + "@vitest/snapshot" "2.1.8" + "@vitest/spy" "2.1.8" + "@vitest/utils" "2.1.8" + chai "^5.1.2" + debug "^4.3.7" + expect-type "^1.1.0" + magic-string "^0.30.12" + pathe "^1.1.2" + std-env "^3.8.0" + tinybench "^2.9.0" + tinyexec "^0.3.1" + tinypool "^1.0.1" + tinyrainbow "^1.2.0" + vite "^5.0.0" + vite-node "2.1.8" + why-is-node-running "^2.3.0" + +w3c-xmlserializer@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" + integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== + dependencies: + xml-name-validator "^5.0.0" + +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + +whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== + dependencies: + iconv-lite "0.6.3" + +whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== + +whatwg-url@^14.0.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.1.0.tgz#fffebec86cc8e6c2a657e50dc606207b870f0ab3" + integrity sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w== + dependencies: + tr46 "^5.0.0" + webidl-conversions "^7.0.0" + +why-is-node-running@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" + integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" + +ws@^8.18.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + +xml-name-validator@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" + integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== From de877cbed5b5b6e24754254f7ac7e2c052bb8f26 Mon Sep 17 00:00:00 2001 From: Gyeongmin Kim Date: Wed, 8 Jan 2025 21:24:38 +0900 Subject: [PATCH 09/11] =?UTF-8?q?feat:=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EB=B6=84=EB=A6=AC=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/basic/const/Day.js | 9 +++ src/basic/const/Discount.js | 14 +++++ src/basic/const/productList.js | 12 ++-- src/basic/services/calculateCart.js | 79 ++++++++++++++++++++++++ src/basic/services/renderBonusPoint.js | 13 ++++ src/basic/services/updateSelectOption.js | 15 +++++ src/basic/services/updateStock.js | 16 +++++ 7 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 src/basic/const/Day.js create mode 100644 src/basic/const/Discount.js create mode 100644 src/basic/services/calculateCart.js create mode 100644 src/basic/services/renderBonusPoint.js create mode 100644 src/basic/services/updateSelectOption.js create mode 100644 src/basic/services/updateStock.js diff --git a/src/basic/const/Day.js b/src/basic/const/Day.js new file mode 100644 index 00000000..f79158d7 --- /dev/null +++ b/src/basic/const/Day.js @@ -0,0 +1,9 @@ +export const Day = { + Sunday: 0, + Monday: 1, + Tuesday: 2, + Wednesday: 3, + Thursday: 4, + Friday: 5, + Saturday: 6, +}; diff --git a/src/basic/const/Discount.js b/src/basic/const/Discount.js new file mode 100644 index 00000000..bd443be1 --- /dev/null +++ b/src/basic/const/Discount.js @@ -0,0 +1,14 @@ +export const DiscountRate = { + Tuesday: 0.1, + Bulk: 0.25, + P1: 0.1, + P2: 0.15, + P3: 0.2, + P4: 0.05, + P5: 0.25, +}; + +export const DiscountedRate = { + lucky: 0.8, + suggest: 0.95, +}; diff --git a/src/basic/const/productList.js b/src/basic/const/productList.js index 4c33c37d..0e041c7a 100644 --- a/src/basic/const/productList.js +++ b/src/basic/const/productList.js @@ -1,7 +1,7 @@ -export var prodList = [ - { id: "p1", name: "상품1", value: 10000, quantity: 50 }, - { id: "p2", name: "상품2", value: 20000, quantity: 30 }, - { id: "p3", name: "상품3", value: 30000, quantity: 20 }, - { id: "p4", name: "상품4", value: 15000, quantity: 0 }, - { id: "p5", name: "상품5", value: 25000, quantity: 10 }, +export const ProductList = [ + { id: 'p1', name: '상품1', price: 10000, quantity: 50 }, + { id: 'p2', name: '상품2', price: 20000, quantity: 30 }, + { id: 'p3', name: '상품3', price: 30000, quantity: 20 }, + { id: 'p4', name: '상품4', price: 15000, quantity: 0 }, + { id: 'p5', name: '상품5', price: 25000, quantity: 10 }, ]; diff --git a/src/basic/services/calculateCart.js b/src/basic/services/calculateCart.js new file mode 100644 index 00000000..d9d6b3a8 --- /dev/null +++ b/src/basic/services/calculateCart.js @@ -0,0 +1,79 @@ +import { Day } from "../const/day"; +import { Discount } from "../const/discount"; +import { renderBonusPoint } from "./renderBonusPoint"; +import { updateStock } from "./updateStock"; + +// 장바구니 계산 +export function calculateCart() { + totalAmount = 0; + itemCounts = 0; + + const cartItems = cartDisplay.children; + let subTotal = 0; + + for (let i = 0; i < cartItems.length; i++) { + (function () { + let currentItem; + for (let j = 0; j < productList.length; j++) { + if (productList[j].id === cartItems[i].id) { + currentItem = productList[j]; + break; + } + } + + let quantity = parseInt( + cartItems[i].querySelector("span").textContent.split("x ")[1] + ); + let itemTotal = currentItem.value * quantity; + let discount = 0; + + itemCounts += quantity; + subTotal += itemTotal; + + if (10 <= quantity) { + if (currentItem.id === "p1") discount = Discount.P1; + else if (currentItem.id === "p2") discount = Discount.P2; + else if (currentItem.id === "p3") discount = Discount.P3; + else if (currentItem.id === "p4") discount = Discount.P4; + else if (currentItem.id === "p5") discount = Discount.P5; + } + + totalAmount += itemTotal * (1 - discount); + })(); + } + + let discountRate = 0; + + // 30개 이상 구매: 대량구매 25% 할인 + if (30 <= itemCounts) { + const bulkDiscount = totalAmount * Discount.Bulk; + const itemDiscount = subTotal - totalAmount; + + if (itemDiscount < bulkDiscount) { + totalAmount = subTotal * (1 - Discount.Bulk); + discountRate = Discount.Bulk; + } else { + discountRate = (subTotal - totalAmount) / subTotal; + } + } else { + discountRate = (subTotal - totalAmount) / subTotal; + } + + // 화요일(2)이면 10% 할인 + if (new Date().getDay() === Day.Tuesday) { + totalAmount *= 1 - Discount.Tuesday; + discountRate = Math.max(discountRate, Discount.Tuesday); + } + + sum.textContent = "총액: " + Math.round(totalAmount) + "원"; + + if (0 < discountRate) { + const span = document.createElement("span"); + span.className = "text-green-500 ml-2"; + span.textContent = "(" + (discountRate * 100).toFixed(1) + "% 할인 적용)"; + sum.appendChild(span); + } + + updateStock(); + renderBonusPoint(totalAmount); +} diff --git a/src/basic/services/renderBonusPoint.js b/src/basic/services/renderBonusPoint.js new file mode 100644 index 00000000..399fa045 --- /dev/null +++ b/src/basic/services/renderBonusPoint.js @@ -0,0 +1,13 @@ +// 포인트 계산 +export const renderBonusPoint = (totalAmount) => { + bonusPoints = Math.floor(totalAmount / 1000); + + let pointsTag = document.getElementById("loyalty-points"); + if (!pointsTag) { + pointsTag = document.createElement("span"); + pointsTag.id = "loyalty-points"; + pointsTag.className = "text-blue-500 ml-2"; + sum.appendChild(pointsTag); + } + pointsTag.textContent = "(포인트: " + bonusPoints + ")"; +}; diff --git a/src/basic/services/updateSelectOption.js b/src/basic/services/updateSelectOption.js new file mode 100644 index 00000000..d2c885ff --- /dev/null +++ b/src/basic/services/updateSelectOption.js @@ -0,0 +1,15 @@ +// 상품 업데이트 +export function updateSelectOptions() { + select.innerHTML = ""; + productList.forEach(function (item) { + let option = document.createElement("option"); + option.value = item.id; + option.textContent = item.name + " - " + item.value + "원"; + + if (item.quantity === 0) { + option.disabled = true; + } + + select.appendChild(option); + }); +} diff --git a/src/basic/services/updateStock.js b/src/basic/services/updateStock.js new file mode 100644 index 00000000..fb3a903e --- /dev/null +++ b/src/basic/services/updateStock.js @@ -0,0 +1,16 @@ +// 재고 정보 업데이트 +export function updateStock() { + let infoMessage = ""; + productList.forEach(function (item) { + if (item.quantity < 5) { + infoMessage += + item.name + + ": " + + (item.quantity > 0 + ? "재고 부족 (" + item.quantity + "개 남음)" + : "품절") + + "\n"; + } + }); + stockInfo.textContent = infoMessage; +} From 30643b7a9b86dd549edefc93e7c132080c8903b9 Mon Sep 17 00:00:00 2001 From: Gyeongmin Kim Date: Wed, 8 Jan 2025 21:25:25 +0900 Subject: [PATCH 10/11] =?UTF-8?q?feat:=20=EB=A7=A4=EC=A7=81=EB=84=98?= =?UTF-8?q?=EB=B2=84=EB=A5=BC=20=EC=83=81=EC=88=98=EC=B2=98=EB=A6=AC,=20?= =?UTF-8?q?=ED=83=9C=EA=B7=B8=20=EC=B6=94=EA=B0=80,=20=EB=B6=80=EB=93=B1?= =?UTF-8?q?=ED=98=B8=20=EB=B0=A9=ED=96=A5=20=EB=B3=80=EA=B2=BD=20=EB=93=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/basic/main.basic.js | 360 ++++++++++++---------------------------- 1 file changed, 107 insertions(+), 253 deletions(-) diff --git a/src/basic/main.basic.js b/src/basic/main.basic.js index 021bb9da..0958d29f 100644 --- a/src/basic/main.basic.js +++ b/src/basic/main.basic.js @@ -1,311 +1,165 @@ -var productList, select, addButton, cartDisplay, sum, stockInfo; +import { DiscountedRate } from './const/discount'; +import { calculateCart } from './services/calculateCart'; +import { updateSelectOptions } from './services/updateSelectOption'; -var lastSell, +let productList, select, addButton, cartDisplay, sum, stockInfo; + +let lastSell, bonusPoints = 0, totalAmount = 0, itemCounts = 0; function main() { - var root = document.getElementById("app"); - - let cont = document.createElement("div"); - cont.className = "bg-gray-100 p-8"; - - var wrap = document.createElement("div"); - wrap.className = - "max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl p-8"; - - let hText = document.createElement("h1"); - hText.className = "text-2xl font-bold mb-4"; - hText.textContent = "장바구니"; - - cartDisplay = document.createElement("div"); - cartDisplay.id = "cart-items"; - - sum = document.createElement("div"); - sum.id = "cart-total"; - sum.className = "text-xl font-bold my-4"; - - select = document.createElement("select"); - select.id = "product-select"; - select.className = "border rounded p-2 mr-2"; - - addButton = document.createElement("button"); - addButton.id = "add-to-cart"; - addButton.className = "bg-blue-500 text-white px-4 py-2 rounded"; - addButton.textContent = "추가"; - - stockInfo = document.createElement("div"); - stockInfo.id = "stock-status"; - stockInfo.className = "text-sm text-gray-500 mt-2"; - - updateSelectOptions(); - - wrap.appendChild(hText); - wrap.appendChild(cartDisplay); - wrap.appendChild(sum); - wrap.appendChild(select); - wrap.appendChild(addButton); - wrap.appendChild(stockInfo); - cont.appendChild(wrap); - root.appendChild(cont); - - calcCart(); - - // 번개세일 할인 이벤트 - setTimeout(function () { - setInterval(function () { - var luckyItem = - productList[Math.floor(Math.random() * productList.length)]; - if (Math.random() < 0.3 && 0 < luckyItem.quantity) { - luckyItem.value = Math.round(luckyItem.value * 0.8); - alert("번개세일! " + luckyItem.name + "이(가) 20% 할인 중입니다!"); - updateSelectOptions(); - } - }, 30000); - }, Math.random() * 10000); - - // 추천상품 할인 이베트 - setTimeout(function () { - setInterval(function () { - if (lastSell) { - var suggest = productList.find(function (item) { - return item.id !== lastSell && 0 < item.quantity; - }); - if (suggest) { - alert( - suggest.name + "은(는) 어떠세요? 지금 구매하시면 5% 추가 할인!" - ); - suggest.value = Math.round(suggest.value * 0.95); - updateSelectOptions(); - } - } - }, 60000); - }, Math.random() * 20000); + return ( + <> +
+
+
+

+ 장바구니 +

+
+
+ + +
+
+ + ); } -// 상품 업데이트 -function updateSelectOptions() { - select.innerHTML = ""; - productList.forEach(function (item) { - var option = document.createElement("option"); - option.value = item.id; - option.textContent = item.name + " - " + item.value + "원"; +updateSelectOptions(); - if (item.quantity === 0) { - option.disabled = true; - } - - select.appendChild(option); - }); -} - -// 장바구니 계산 -function calcCart() { - totalAmount = 0; - itemCounts = 0; - - var cartItems = cartDisplay.children; - var subTotal = 0; - - for (var i = 0; i < cartItems.length; i++) { - (function () { - var currentItem; - for (var j = 0; j < productList.length; j++) { - if (productList[j].id === cartItems[i].id) { - currentItem = productList[j]; - break; - } - } +calculateCart(); - var quantity = parseInt( - cartItems[i].querySelector("span").textContent.split("x ")[1] - ); - var itemTotal = currentItem.value * quantity; - var discount = 0; - - itemCounts += quantity; - subTotal += itemTotal; - - if (quantity >= 10) { - if (currentItem.id === "p1") discount = 0.1; - else if (currentItem.id === "p2") discount = 0.15; - else if (currentItem.id === "p3") discount = 0.2; - else if (currentItem.id === "p4") discount = 0.05; - else if (currentItem.id === "p5") discount = 0.25; - } - - totalAmount += itemTotal * (1 - discount); - })(); - } - - let discountRate = 0; - - // 30개 이상 구매: 대량구매 25% 할인 - if (itemCounts >= 30) { - var bulkDiscount = totalAmount * 0.25; - var itemDiscount = subTotal - totalAmount; - - if (bulkDiscount > itemDiscount) { - totalAmount = subTotal * (1 - 0.25); - discountRate = 0.25; - } else { - discountRate = (subTotal - totalAmount) / subTotal; +// 번개세일 할인 이벤트 +setTimeout(function () { + setInterval(function () { + const luckyItem = productList[Math.floor(Math.random() * productList.length)]; + if (Math.random() < 0.3 && 0 < luckyItem.quantity) { + luckyItem.price = Math.round(luckyItem.price * DiscountedRate.lucky); + alert('번개세일! ' + luckyItem.name + '이(가) 20% 할인 중입니다!'); + updateSelectOptions(); } - } else { - discountRate = (subTotal - totalAmount) / subTotal; - } - - // 화요일(2)이면 10% 할인 - if (new Date().getDay() === 2) { - totalAmount *= 1 - 0.1; - discountRate = Math.max(discountRate, 0.1); - } - - sum.textContent = "총액: " + Math.round(totalAmount) + "원"; - - if (discountRate > 0) { - var span = document.createElement("span"); - span.className = "text-green-500 ml-2"; - span.textContent = "(" + (discountRate * 100).toFixed(1) + "% 할인 적용)"; - sum.appendChild(span); - } - - updateStockInfo(); - renderBonusPts(); -} - -// 포인트 계산 -const renderBonusPts = () => { - bonusPoints = Math.floor(totalAmount / 1000); - - var pointsTag = document.getElementById("loyalty-points"); - if (!pointsTag) { - pointsTag = document.createElement("span"); - pointsTag.id = "loyalty-points"; - pointsTag.className = "text-blue-500 ml-2"; - sum.appendChild(pointsTag); - } - pointsTag.textContent = "(포인트: " + bonusPoints + ")"; -}; - -// 재고 정보 업데이트 -function updateStockInfo() { - var infoMessage = ""; - productList.forEach(function (item) { - if (item.quantity < 5) { - infoMessage += - item.name + - ": " + - (item.quantity > 0 - ? "재고 부족 (" + item.quantity + "개 남음)" - : "품절") + - "\n"; + }, 30000); +}, Math.random() * 10000); + +// 추천상품 할인 이벤트 +setTimeout(function () { + setInterval(function () { + if (lastSell) { + const suggest = productList.find(function (item) { + return item.id !== lastSell && 0 < item.quantity; + }); + if (suggest) { + alert(suggest.name + '은(는) 어떠세요? 지금 구매하시면 5% 추가 할인!'); + suggest.price = Math.round(suggest.price * DiscountedRate.suggest); + updateSelectOptions(); + } } - }); - stockInfo.textContent = infoMessage; -} + }, 60000); +}, Math.random() * 20000); main(); // addButton 클릭시 이벤트 등록 -addButton.addEventListener("click", function () { - var selectedItem = select.value; - var itemToAdd = productList.find(function (p) { +addButton.addEventListener('click', function () { + const selectedItem = select.price; + const itemToAdd = productList.find(function (p) { return p.id === selectedItem; }); - if (itemToAdd && itemToAdd.quantity > 0) { - var item = document.getElementById(itemToAdd.id); + if (itemToAdd && 0 < itemToAdd.quantity) { + let item = document.getElementById(itemToAdd.id); if (item) { - var newQuantity = - parseInt(item.querySelector("span").textContent.split("x ")[1]) + 1; + let newQuantity = parseInt(item.querySelector('span').textContent.split('x ')[1]) + 1; if (newQuantity <= itemToAdd.quantity) { - item.querySelector("span").textContent = - itemToAdd.name + " - " + itemToAdd.value + "원 x " + newQuantity; + item.querySelector('span').textContent = + itemToAdd.name + ' - ' + itemToAdd.price + '원 x ' + newQuantity; itemToAdd.quantity--; } else { - alert("재고가 부족합니다."); + alert('재고가 부족합니다.'); } } else { - var newItem = document.createElement("div"); - newItem.id = itemToAdd.id; - newItem.className = "flex justify-between items-center mb-2"; - newItem.innerHTML = - "" + - itemToAdd.name + - " - " + - itemToAdd.value + - "원 x 1
" + - '' + - '' + - '
'; +
+ + {itemToAdd.name} - {itemToAdd.price}원 x 1 + +
+ + + +
+
; cartDisplay.appendChild(newItem); itemToAdd.quantity--; } - calcCart(); + calculateCart(); lastSell = selItem; } }); // cartDisplay 클릭시 이벤트 등록 -cartDisplay.addEventListener("click", function (event) { - var target = event.target; - if ( - target.classList.contains("quantity-change") || - target.classList.contains("remove-item") - ) { - var productId = target.dataset.productId; - var itemElement = document.getElementById(productId); - var product = productList.find(function (p) { +cartDisplay.addEventListener('click', function (event) { + let target = event.target; + if (target.classList.contains('quantity-change') || target.classList.contains('remove-item')) { + let productId = target.dataset.productId; + let itemElement = document.getElementById(productId); + let product = productList.find(function (p) { return p.id === productId; }); - if (target.classList.contains("quantity-change")) { - var quantityChange = parseInt(target.dataset.change); - var newQuantity = - parseInt(itemElement.querySelector("span").textContent.split("x ")[1]) + - quantityChange; + if (target.classList.contains('quantity-change')) { + let quantityChange = parseInt(target.dataset.change); + let newQuantity = + parseInt(itemElement.querySelector('span').textContent.split('x ')[1]) + quantityChange; if ( - newQuantity > 0 && + 0 < newQuantity && newQuantity <= - product.quantity + - parseInt( - itemElement.querySelector("span").textContent.split("x ")[1] - ) + product.quantity + parseInt(itemElement.querySelector('span').textContent.split('x ')[1]) ) { - itemElement.querySelector("span").textContent = - itemElement.querySelector("span").textContent.split("x ")[0] + - "x " + - newQuantity; + itemElement.querySelector('span').textContent = + itemElement.querySelector('span').textContent.split('x ')[0] + 'x ' + newQuantity; product.quantity -= quantityChange; } else if (newQuantity <= 0) { itemElement.remove(); product.quantity -= quantityChange; } else { - alert("재고가 부족합니다."); + alert('재고가 부족합니다.'); } - } else if (target.classList.contains("remove-item")) { - var removeQuantity = parseInt( - itemElement.querySelector("span").textContent.split("x ")[1] - ); + } else if (target.classList.contains('remove-item')) { + let removeQuantity = parseInt(itemElement.querySelector('span').textContent.split('x ')[1]); product.quantity += removeQuantity; itemElement.remove(); } - calcCart(); + calculateCart(); } }); From 7882803de15df84c6795af0a618c633bf5dc941c Mon Sep 17 00:00:00 2001 From: Gyeongmin Kim Date: Fri, 10 Jan 2025 09:44:53 +0900 Subject: [PATCH 11/11] =?UTF-8?q?=EC=9E=91=EC=97=85=EC=9D=84=20=EC=A4=91?= =?UTF-8?q?=EB=8B=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/advanced/App.tsx | 3 ++ src/advanced/index.html | 1 + src/advanced/index.tsx | 9 ++++++ src/advanced/tsconfig.json | 0 src/basic/main.basic.js | 10 +++--- src/basic/services/calculateCart.js | 40 +++++++++++------------- src/basic/services/renderBonusPoint.js | 11 ++++--- src/basic/services/updateSelectOption.js | 6 ++-- src/basic/services/updateStock.js | 10 +++--- src/basic/stores/cartStore.js | 19 +++++++++++ 10 files changed, 67 insertions(+), 42 deletions(-) create mode 100644 src/advanced/App.tsx create mode 100644 src/advanced/index.html create mode 100644 src/advanced/index.tsx create mode 100644 src/advanced/tsconfig.json create mode 100644 src/basic/stores/cartStore.js diff --git a/src/advanced/App.tsx b/src/advanced/App.tsx new file mode 100644 index 00000000..1f1b34b9 --- /dev/null +++ b/src/advanced/App.tsx @@ -0,0 +1,3 @@ +export default function App() { + return
App
; +} diff --git a/src/advanced/index.html b/src/advanced/index.html new file mode 100644 index 00000000..e2fcc54e --- /dev/null +++ b/src/advanced/index.html @@ -0,0 +1 @@ +
diff --git a/src/advanced/index.tsx b/src/advanced/index.tsx new file mode 100644 index 00000000..603a8d06 --- /dev/null +++ b/src/advanced/index.tsx @@ -0,0 +1,9 @@ +import App from "./App"; +import React from "react"; +import ReactDOM from "react-dom/client"; + +const root = ReactDOM.createRoot( + document.getElementById("root") as HTMLElement +); + +root.render(); diff --git a/src/advanced/tsconfig.json b/src/advanced/tsconfig.json new file mode 100644 index 00000000..e69de29b diff --git a/src/basic/main.basic.js b/src/basic/main.basic.js index 0958d29f..911e3425 100644 --- a/src/basic/main.basic.js +++ b/src/basic/main.basic.js @@ -5,15 +5,13 @@ import { updateSelectOptions } from './services/updateSelectOption'; let productList, select, addButton, cartDisplay, sum, stockInfo; let lastSell, - bonusPoints = 0, - totalAmount = 0, - itemCounts = 0; + bonusPoints = 0; function main() { return ( <>
-
+
({(discountRate * 100).toFixed(1)} % 할인 적용); sum.appendChild(span); } diff --git a/src/basic/services/renderBonusPoint.js b/src/basic/services/renderBonusPoint.js index 399fa045..d63cfeed 100644 --- a/src/basic/services/renderBonusPoint.js +++ b/src/basic/services/renderBonusPoint.js @@ -2,12 +2,13 @@ export const renderBonusPoint = (totalAmount) => { bonusPoints = Math.floor(totalAmount / 1000); - let pointsTag = document.getElementById("loyalty-points"); + let pointsTag = document.getElementById('loyalty-points'); if (!pointsTag) { - pointsTag = document.createElement("span"); - pointsTag.id = "loyalty-points"; - pointsTag.className = "text-blue-500 ml-2"; + ; + // pointsTag = document.createElement('span'); + // pointsTag.id = 'loyalty-points'; + // pointsTag.className = 'text-blue-500 ml-2'; sum.appendChild(pointsTag); } - pointsTag.textContent = "(포인트: " + bonusPoints + ")"; + pointsTag.textContent = `(포인트: ${bonusPoints})`; }; diff --git a/src/basic/services/updateSelectOption.js b/src/basic/services/updateSelectOption.js index d2c885ff..b7d61660 100644 --- a/src/basic/services/updateSelectOption.js +++ b/src/basic/services/updateSelectOption.js @@ -1,10 +1,10 @@ // 상품 업데이트 export function updateSelectOptions() { - select.innerHTML = ""; + select.innerHTML = ''; productList.forEach(function (item) { - let option = document.createElement("option"); + let option = document.createElement('option'); option.value = item.id; - option.textContent = item.name + " - " + item.value + "원"; + option.textContent = item.name + ' - ' + item.value + '원'; if (item.quantity === 0) { option.disabled = true; diff --git a/src/basic/services/updateStock.js b/src/basic/services/updateStock.js index fb3a903e..cb8c9d5a 100644 --- a/src/basic/services/updateStock.js +++ b/src/basic/services/updateStock.js @@ -1,15 +1,13 @@ // 재고 정보 업데이트 export function updateStock() { - let infoMessage = ""; + let infoMessage = ''; productList.forEach(function (item) { if (item.quantity < 5) { infoMessage += item.name + - ": " + - (item.quantity > 0 - ? "재고 부족 (" + item.quantity + "개 남음)" - : "품절") + - "\n"; + ': ' + + (item.quantity > 0 ? `재고 부족 (${item.quantity}개 남음)` : '품절') + + '\n'; } }); stockInfo.textContent = infoMessage; diff --git a/src/basic/stores/cartStore.js b/src/basic/stores/cartStore.js new file mode 100644 index 00000000..4a42c343 --- /dev/null +++ b/src/basic/stores/cartStore.js @@ -0,0 +1,19 @@ +export default function cartStore() { + let totalAmount = 0; + let itemCounts = 0; + + const addItemCount = (quantity) => { + state.itemCounts += quantity; + }; + + const addTotalAmount = (amount) => { + totalAmount += amount; + }; + + return { + totalAmount, + itemCounts, + addItemCount, + addTotalAmount, + }; +}