diff --git a/.github/workflows/design-pull-request.yml b/.github/workflows/design-pull-request.yml new file mode 100644 index 000000000..af168a976 --- /dev/null +++ b/.github/workflows/design-pull-request.yml @@ -0,0 +1,54 @@ +name: Storybook Deployment + +on: + pull_request: + branches: + - fe-dev + paths: + - 'HDesign/**' + +jobs: + chromatic: + name: Run Chromatic + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.15.1' + + - name: Cache dependencies + id: cache + uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-npm- + + - name: Install dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: | + cd HDesign + npm install + + - name: Run lint + run: npm run lint + working-directory: ./HDesign + + - name: Run Chromatic + uses: chromaui/action@latest + id: publish_chromatic + with: + workingDir: HDesign + projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + + - name: Comment on PR + uses: thollander/actions-comment-pull-request@v2 + with: + message: '๐Ÿš€ **storybook**: ${{ steps.publish_chromatic.outputs.storybookUrl }}' diff --git a/.github/workflows/frontend-pull-request.yml b/.github/workflows/frontend-pull-request.yml index 913ba783d..c2749939b 100644 --- a/.github/workflows/frontend-pull-request.yml +++ b/.github/workflows/frontend-pull-request.yml @@ -5,7 +5,7 @@ on: types: [opened, synchronize] branches: [main, fe-dev] paths: - - "client/**" + - 'client/**' jobs: test: @@ -23,15 +23,18 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: "20.15.1" + node-version: '20.15.1' - name: Install dependencies + working-directory: ./client run: npm install - name: Run lint + working-directory: ./client run: npm run lint - name: Run test + working-directory: ./client run: npm run test - name: Cypress test @@ -44,48 +47,3 @@ jobs: - name: Run Cypress tests run: npm run cypress-run - - chromatic: - name: Run Chromatic - runs-on: ubuntu-latest - - defaults: - run: - shell: bash - working-directory: ./client - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: "20.15.1" - - - name: Cache dependencies - id: cache - uses: actions/cache@v3 - with: - path: "**/node_modules" - key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}-v1 - restore-keys: | - ${{ runner.os }}-npm- - - - name: Install dependencies - if: steps.cache.outputs.cache-hit != 'true' - run: npm install - - - name: Run Chromatic - uses: chromaui/action@latest - id: publish_chromatic - with: - workingDir: client - projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} - - - name: Comment on PR - uses: thollander/actions-comment-pull-request@v2 - with: - message: "๐Ÿš€ **storybook**: ${{ steps.publish_chromatic.outputs.storybookUrl }}" diff --git a/HDesign/.gitignore b/HDesign/.gitignore new file mode 100644 index 000000000..b98928456 --- /dev/null +++ b/HDesign/.gitignore @@ -0,0 +1,12 @@ +logs +*.log +npm-debug.log* + +node_modules +dist + +.env + +storybook-static +*storybook.log +.DS_Store diff --git a/HDesign/.npmignore b/HDesign/.npmignore new file mode 100644 index 000000000..363c89306 --- /dev/null +++ b/HDesign/.npmignore @@ -0,0 +1,7 @@ +node_modules/ +src/ +tsconfig.json +.storybook/ +.eslintrc.json +.prettierrc +webpack.config.js \ No newline at end of file diff --git a/HDesign/.npmrc b/HDesign/.npmrc new file mode 100644 index 000000000..ece05f588 --- /dev/null +++ b/HDesign/.npmrc @@ -0,0 +1,2 @@ +engine-strict = true +legacy-peer-deps = true diff --git a/HDesign/.prettierrc b/HDesign/.prettierrc new file mode 100644 index 000000000..c025201f4 --- /dev/null +++ b/HDesign/.prettierrc @@ -0,0 +1,12 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "printWidth": 120, + "tabWidth": 2, + "semi": true, + "arrowParens": "avoid", + "endOfLine": "auto", + "jsxSingleQuote": false, + "bracketSpacing": false, + "proseWrap": "preserve" +} diff --git a/HDesign/.storybook/main.ts b/HDesign/.storybook/main.ts new file mode 100644 index 000000000..a1fa61591 --- /dev/null +++ b/HDesign/.storybook/main.ts @@ -0,0 +1,47 @@ +/** @type { import('@storybook/react-webpack5').StorybookConfig } */ +import type {StorybookConfig} from '@storybook/react-webpack5'; +import path from 'path'; + +const config: StorybookConfig = { + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + addons: [ + '@storybook/addon-webpack5-compiler-swc', + '@storybook/addon-onboarding', + '@storybook/addon-links', + '@storybook/addon-essentials', + '@chromatic-com/storybook', + '@storybook/addon-interactions', + ], + framework: { + name: '@storybook/react-webpack5', + options: {}, + }, + webpackFinal: async config => { + if (config.resolve) { + config.resolve.alias = { + ...config.resolve.alias, + '@components': path.resolve(__dirname, '../src/components'), + '@token': path.resolve(__dirname, '../src/token'), + '@type': path.resolve(__dirname, '../src/type'), + '@theme': path.resolve(__dirname, '../src/theme'), + '@assets': path.resolve(__dirname, '../src/assets'), + '@utils': path.resolve(__dirname, '../src/utils'), + }; + } + + config.module = config.module || {}; + config.module.rules = config.module.rules || []; + + const imageRule = config.module.rules.find(rule => rule?.['test']?.test('.svg')); + if (imageRule) { + imageRule['exclude'] = /\.svg$/; + } + + config.module.rules.push({ + test: /\.svg$/, + use: ['@svgr/webpack'], + }); + return config; + }, +}; +export default config; diff --git a/client/.storybook/preview.tsx b/HDesign/.storybook/preview.tsx similarity index 91% rename from client/.storybook/preview.tsx rename to HDesign/.storybook/preview.tsx index a3c83803f..22008ad03 100644 --- a/client/.storybook/preview.tsx +++ b/HDesign/.storybook/preview.tsx @@ -1,7 +1,7 @@ /** @jsxImportSource @emotion/react */ import type {Preview} from '@storybook/react'; -import {HDesignProvider} from '../src/components/Design'; +import {HDesignProvider} from '../src/theme/HDesignProvider'; const preview: Preview = { parameters: { diff --git a/HDesign/eslint.config.mjs b/HDesign/eslint.config.mjs new file mode 100644 index 000000000..e025936a4 --- /dev/null +++ b/HDesign/eslint.config.mjs @@ -0,0 +1,153 @@ +import path from 'node:path'; +import {fileURLToPath} from 'node:url'; + +import {fixupConfigRules, fixupPluginRules} from '@eslint/compat'; +import react from 'eslint-plugin-react'; +import typescriptEslint from '@typescript-eslint/eslint-plugin'; +import _import from 'eslint-plugin-import'; +import prettier from 'eslint-plugin-prettier'; +import tsParser from '@typescript-eslint/parser'; +import js from '@eslint/js'; +import {FlatCompat} from '@eslint/eslintrc'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all, +}); + +export default [ + ...fixupConfigRules( + compat.extends( + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + 'plugin:import/typescript', + 'plugin:import/recommended', + 'plugin:import/errors', + 'plugin:import/warnings', + 'prettier', + 'plugin:prettier/recommended', + ), + ), + { + plugins: { + react: fixupPluginRules(react), + '@typescript-eslint': fixupPluginRules(typescriptEslint), + import: fixupPluginRules(_import), + prettier: fixupPluginRules(prettier), + }, + + languageOptions: { + parser: tsParser, + }, + + settings: { + 'import/resolver': { + node: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + + typescript: { + directory: './lib', + }, + }, + + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + + 'import/ignore': ['lottie-react'], + }, + + rules: { + 'no-use-before-define': 0, + 'prettier/prettier': 'error', + 'react/react-in-jsx-scope': 'off', + 'react/prop-types': 'off', + 'import/prefer-default-export': 0, + 'import/no-named-as-default': 0, + 'import/namespace': 0, + 'import/extensions': 0, + 'import/no-cycle': 0, + 'react/no-unknown-property': 0, + 'react/jsx-filename-extension': [1, {extensions: ['.ts', '.tsx']}], + 'react/function-component-definition': 0, + 'react/jsx-props-no-spreading': 0, + 'react/jsx-key': 0, + 'react/button-has-type': 'off', + 'no-shadow': 0, + 'no-console': 0, + 'no-alert': 0, + 'react/no-children-prop': 'off', + 'react/no-array-index-key': 'off', + 'react-hooks/exhaustive-deps': 'off', + 'react-hooks/rules-of-hooks': 'off', + 'react/jsx-no-useless-fragment': 'off', + 'react/jsx-no-constructed-context-values': 'off', + 'jsx-a11y/click-events-have-key-events': 'off', + 'jsx-a11y/no-static-element-interactions': 'off', + + '@typescript-eslint/no-unused-vars': 0, + + // 'react/jsx-uses-vars': 'error', + // '@typescript-eslint/no-use-before-define': ['error'], + // '@typescript-eslint/explicit-module-boundary-types': 'error', + + 'import/order': [ + 'error', + { + 'newlines-between': 'always', + + groups: ['type', 'builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'unknown'], + + pathGroups: [ + { + pattern: 'react*', + group: 'external', + position: 'before', + }, + { + pattern: '@components/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@layouts/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@assets/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@theme/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@token/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@types/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@utils/*', + group: 'internal', + position: 'after', + }, + ], + }, + ], + }, + }, +]; diff --git a/HDesign/package-lock.json b/HDesign/package-lock.json new file mode 100644 index 000000000..fb92d2ae1 --- /dev/null +++ b/HDesign/package-lock.json @@ -0,0 +1,13707 @@ +{ + "name": "haengdong-design", + "version": "0.1.81", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "haengdong-design", + "version": "0.1.81", + "license": "ISC", + "dependencies": { + "@emotion/react": "^11.11.4", + "@storybook/addon-webpack5-compiler-swc": "^1.0.5", + "@svgr/webpack": "^8.1.0", + "lottie-react": "^2.4.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "devDependencies": { + "@chromatic-com/storybook": "^1.6.1", + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", + "@storybook/addon-essentials": "^8.2.2", + "@storybook/addon-interactions": "^8.2.2", + "@storybook/addon-links": "^8.2.2", + "@storybook/addon-onboarding": "^8.2.2", + "@storybook/blocks": "^8.2.2", + "@storybook/react": "^8.2.2", + "@storybook/react-webpack5": "^8.2.3", + "@storybook/test": "^8.2.2", + "@swc/core": "^1.7.6", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "esbuild": "^0.23.0", + "eslint": "^9.8.0", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.4", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-storybook": "^0.8.0", + "file-loader": "^6.2.0", + "globals": "^15.8.0", + "prettier": "3.3.2", + "storybook": "^8.2.2", + "storybook-addon-react-router-v6": "^2.0.15", + "ts-loader": "^9.5.1", + "tsc-alias": "^1.8.10", + "typescript": "^5.5.3", + "typescript-eslint": "^7.16.0" + }, + "engines": { + "node": ">=20.15.1", + "npm": ">=10.7.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", + "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", + "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", + "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.9", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-module-transforms": "^7.24.9", + "@babel/helpers": "^7.24.8", + "@babel/parser": "^7.24.8", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", + "integrity": "sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==", + "dependencies": { + "@babel/types": "^7.24.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", + "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "dependencies": { + "@babel/compat-data": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", + "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", + "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dependencies": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", + "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", + "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-wrap-function": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", + "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", + "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "dependencies": { + "@babel/helper-function-name": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", + "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", + "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", + "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", + "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.7.tgz", + "integrity": "sha512-9G8GYT/dxn/D1IIKOUBmGX0mnmj46mGH9NnZyJLwtCpgh5f7D2VbuKodb+2s9m1Yavh1s7ASQN8lf0eqrb1LTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", + "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", + "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", + "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", + "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", + "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.7.tgz", + "integrity": "sha512-cjRKJ7FobOH2eakx7Ja+KpJRj8+y+/SiB3ooYm/n2UJfxu0oEaOoxOinitkJcPqv9KxS0kxTGPUaR7L2XcXDXA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-flow": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", + "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", + "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", + "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", + "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.24.7.tgz", + "integrity": "sha512-7LidzZfUXyfZ8/buRW6qIIHBY8wAZ1OrY9c/wTr8YhZ6vMPo+Uc/CVFLYY1spZrEQlD4w5u8wjqk5NQ3OVqQKA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", + "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", + "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", + "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", + "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.8.tgz", + "integrity": "sha512-CgFgtN61BbdOGCP4fLaAMOPkzWUh6yQZNMr5YSt8uz2cZSSiQONCQFWqsE4NeVfOIhqDOlS9CR3WD91FzMeB2Q==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/plugin-syntax-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", + "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz", + "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==", + "dependencies": { + "@babel/compat-data": "^7.24.8", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.24.7", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.24.7", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.24.8", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.24.7", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.24.7", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-flow": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.7.tgz", + "integrity": "sha512-NL3Lo0NorCU607zU3NwRyJbpaB6E3t0xtd3LfAQKDfkeX4/ggcDXvkmkW42QWT5owUeW/jAe4hn+2qvkV1IbfQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-flow-strip-types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", + "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.24.7", + "@babel/plugin-transform-react-jsx-development": "^7.24.7", + "@babel/plugin-transform-react-pure-annotations": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", + "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.24.6.tgz", + "integrity": "sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.6", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/register/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "node_modules/@babel/runtime": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", + "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.8", + "@babel/types": "^7.24.8", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/types": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", + "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@base2/pretty-print-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", + "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", + "dev": true + }, + "node_modules/@chromatic-com/storybook": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-1.6.1.tgz", + "integrity": "sha512-x1x1NB3j4xpfeSWKr96emc+7ZvfsvH+/WVb3XCjkB24PPbT8VZXb3mJSAQMrSzuQ8+eQE9kDogYHH9Fj3tb/Cw==", + "dev": true, + "dependencies": { + "chromatic": "^11.4.0", + "filesize": "^10.0.12", + "jsonfile": "^6.1.0", + "react-confetti": "^6.1.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16.0.0", + "yarn": ">=1.22.18" + } + }, + "node_modules/@chromatic-com/storybook/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@chromatic-com/storybook/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", + "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", + "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.0.tgz", + "integrity": "sha512-s9Wi/p25+KbzxKlDm3VshQdImhWk+cbdblhwGNnyCU5lpSwtWa4v7VQCxSki0FAUrGA3s8nCWgYzAH41mwQVKQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", + "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz", + "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==", + "dev": true, + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@remix-run/router": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.1.tgz", + "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/addon-actions": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.2.2.tgz", + "integrity": "sha512-SN4cSRt3f0qXi5te+yhMseSdQuZntA8lGlASbRmN77YQTpIaGsNiH88xFoky0s9qz531hiRfU1R0ZSMylBwSKw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@types/uuid": "^9.0.1", + "dequal": "^2.0.2", + "polished": "^4.2.2", + "uuid": "^9.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-actions/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@storybook/addon-backgrounds": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.2.2.tgz", + "integrity": "sha512-m/xJe7uKL+kfJx7pQcHwAeIvJ3tdLIpDGrMAVDNDJHcAxfe44cFjIInaV/1HKf3y5Awap+DZFW66ekkxuI9zzA==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-controls": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.2.2.tgz", + "integrity": "sha512-y241aOANGzT5XBADUIvALwG/xF5eC6UItzmWJaFvOzSBCq74GIA0+Hu9atyFdvFQbXOrdvPWC4jR+9iuBFRxAA==", + "dev": true, + "dependencies": { + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-docs": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.2.2.tgz", + "integrity": "sha512-qk/yjAR9RpsSrKLLbeCgb6u58c8TmYqyJSnXgbAozZZNKHBWlIpvZ/hTNYud8qo0coPlxnLdjnZf32TykWGlAg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@mdx-js/react": "^3.0.0", + "@storybook/blocks": "8.2.2", + "@storybook/csf-plugin": "8.2.2", + "@storybook/global": "^5.0.0", + "@storybook/react-dom-shim": "8.2.2", + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "fs-extra": "^11.1.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "rehype-external-links": "^3.0.0", + "rehype-slug": "^6.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-docs/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@storybook/addon-essentials": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.2.2.tgz", + "integrity": "sha512-yN//BFMbSvNV0+Sll2hcKmgJX06TUKQDm6pZimUjkXczFtOmK7K/UdDmKjWS+qjhfJdWpxdRoEpxoHvvRmNfsA==", + "dev": true, + "dependencies": { + "@storybook/addon-actions": "8.2.2", + "@storybook/addon-backgrounds": "8.2.2", + "@storybook/addon-controls": "8.2.2", + "@storybook/addon-docs": "8.2.2", + "@storybook/addon-highlight": "8.2.2", + "@storybook/addon-measure": "8.2.2", + "@storybook/addon-outline": "8.2.2", + "@storybook/addon-toolbars": "8.2.2", + "@storybook/addon-viewport": "8.2.2", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-highlight": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.2.2.tgz", + "integrity": "sha512-yDTRzzL+IJAymgY32xoZl09BGBVmPOUV2wVNGYcZkkBLvz2GSQMTfUe1/7F4jAx//+rFBu48/MQzsTC7Bk8kPw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-interactions": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-8.2.2.tgz", + "integrity": "sha512-zRRuUwm/l41JtTUgjIoQTUgLT99Hsdz9cqKca/8NYo1MGBdEcKE41DH4aBIzKaOKFu7p9q00/o/X1EqYX4LMUA==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/instrumenter": "8.2.2", + "@storybook/test": "8.2.2", + "polished": "^4.2.2", + "ts-dedent": "^2.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-links": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-8.2.2.tgz", + "integrity": "sha512-eGh7O7SgTJMtnuXC0HlRPOegu1njcJS2cnVqjbzjvjxsPSBhbHpdYMi9Q9E7al/FKuqMUOjIR9YLIlmK1AJaqA==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-measure": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.2.2.tgz", + "integrity": "sha512-3rCo/aMltt5FrBVdr2dYlD8HlE2q9TLKGJZnwh9on4QyL6ArHbdYw0LmyHe/LrFahJ49w1XQZBMSJcAdRkkS7w==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-onboarding": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-onboarding/-/addon-onboarding-8.2.2.tgz", + "integrity": "sha512-dCdE8Mt/JW6cq6dY7co35Sul/bAkUT3ixaxBrUagFUYUQ/PTYM6p4/B+45RURD5S9z8LVHH1rVgmEeScm3U78w==", + "dev": true, + "dependencies": { + "react-confetti": "^6.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-outline": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.2.2.tgz", + "integrity": "sha512-Y+PQtfTNO8GLX5nz+3x5AMfHNvdGvBXazJ29+Rl1ygYN1+Q9ZhRJDE1kAK0wLxb7CG14peAgdYEaQb3Rduv7HQ==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-toolbars": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.2.2.tgz", + "integrity": "sha512-JGOueOc3EPljlCl9dVSQee0aMYoqGNvN0UH+R6wYJ3bDZ+tUG/iYpsZVPUOvS8vzp3Imk5Is1kzQbQYJtzdGLg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-viewport": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.2.2.tgz", + "integrity": "sha512-gkZ8bsjGGP0NuevkT2iKC+szezSy+w4BrBDknf490mRU2K/B2e7TGojf/j/AtxzILMzD4IKzKUXbE/zwcqjZvA==", + "dev": true, + "dependencies": { + "memoizerific": "^1.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-webpack5-compiler-swc": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@storybook/addon-webpack5-compiler-swc/-/addon-webpack5-compiler-swc-1.0.5.tgz", + "integrity": "sha512-1NlM3noit2vA22OyWb8Ma2lhcEKCS1Snv2kr+EkaVABUqNDfVc9AD/GgYQhF7F/2CoF5N2JU7uzXDzFHd5TzZg==", + "dependencies": { + "@swc/core": "^1.7.3", + "swc-loader": "^0.2.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@storybook/blocks": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.2.2.tgz", + "integrity": "sha512-av0Tryg4toDl2L/d1ABErtsAk9wvM1su6+M4wq5/Go50sk5IjGTldhbZFa9zNOohxLkZwaj0Q5xAgJ1Y+m5KrQ==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@storybook/global": "^5.0.0", + "@storybook/icons": "^1.2.5", + "@types/lodash": "^4.14.167", + "color-convert": "^2.0.1", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "markdown-to-jsx": "^7.4.5", + "memoizerific": "^1.11.3", + "polished": "^4.2.2", + "react-colorful": "^5.1.2", + "telejson": "^7.2.0", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-8.2.3.tgz", + "integrity": "sha512-yU9rtcVpo12vD8m/nbdepyJ09K937ZnSsrvIM9XfzbxXA/+p4Cov9Rjg1VfoWyRd1ApxaztSktQlawBlb6bKEA==", + "dev": true, + "dependencies": { + "@storybook/core-webpack": "8.2.3", + "@types/node": "^18.0.0", + "@types/semver": "^7.3.4", + "browser-assert": "^1.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "cjs-module-lexer": "^1.2.3", + "constants-browserify": "^1.0.0", + "css-loader": "^6.7.1", + "es-module-lexer": "^1.5.0", + "express": "^4.19.2", + "fork-ts-checker-webpack-plugin": "^8.0.0", + "fs-extra": "^11.1.0", + "html-webpack-plugin": "^5.5.0", + "magic-string": "^0.30.5", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "semver": "^7.3.7", + "style-loader": "^3.3.1", + "terser-webpack-plugin": "^5.3.1", + "ts-dedent": "^2.0.0", + "url": "^0.11.0", + "util": "^0.12.4", + "util-deprecate": "^1.0.2", + "webpack": "5", + "webpack-dev-middleware": "^6.1.2", + "webpack-hot-middleware": "^2.25.1", + "webpack-virtual-modules": "^0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.3" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/fork-ts-checker-webpack-plugin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz", + "integrity": "sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/@storybook/builder-webpack5/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.3.tgz", + "integrity": "sha512-A4ChP0Qj8oGociTs6UdlRUGANIGrCDL3y+pmQMc+dSsraXHCatFpmMey4mYELA+juqwUqwQsUgJJISXl1KWmiw==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@storybook/codemod": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-8.2.2.tgz", + "integrity": "sha512-wRUVKLHVUhbLJYKW3QOufUxJGwaUT4jTCD8+HOGpHPdJO3NrwXu186xt4tuPZO2Y/NnacPeCQPsaK5ok4O8o7A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/preset-env": "^7.24.4", + "@babel/types": "^7.24.0", + "@storybook/core": "8.2.2", + "@storybook/csf": "0.1.11", + "@types/cross-spawn": "^6.0.2", + "cross-spawn": "^7.0.3", + "globby": "^14.0.1", + "jscodeshift": "^0.15.1", + "lodash": "^4.17.21", + "prettier": "^3.1.1", + "recast": "^0.23.5", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/codemod/node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/codemod/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/codemod/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/core": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.2.2.tgz", + "integrity": "sha512-L4ojYI+Os/i5bCReDIlFgEDQSS94mbJlNU9WRzEGZpqNC5/hbFEC9Tip7P1MiRx9NrewkzU7b+UCP7mi3e4drQ==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@types/express": "^4.17.21", + "@types/node": "^18.0.0", + "browser-assert": "^1.2.1", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0", + "esbuild-register": "^3.5.0", + "express": "^4.19.2", + "process": "^0.11.10", + "recast": "^0.23.5", + "util": "^0.12.4", + "ws": "^8.2.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-webpack": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.2.3.tgz", + "integrity": "sha512-0M4mJM6i4Oqp1javRMg/8wJW7VJ6p6Z8GKp6evfHLEWZAzdnexQIkPd5FFaDlFXbQNH1H0oJ+6ei4nIBtEegKg==", + "dev": true, + "dependencies": { + "@types/node": "^18.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.3" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/core/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/core/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "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" + } + }, + "node_modules/@storybook/csf": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.11.tgz", + "integrity": "sha512-dHYFQH3mA+EtnCkHXzicbLgsvzYjcDJ1JWsogbItZogkPHgSJM/Wr71uMkcvw8v9mmCyP4NpXJuu6bPoVsOnzg==", + "dev": true, + "dependencies": { + "type-fest": "^2.19.0" + } + }, + "node_modules/@storybook/csf-plugin": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.2.2.tgz", + "integrity": "sha512-3K2RUpDDvq3DT46qAIj2VBC+fzTTebRUcZUsRfS6G1AzaX9p25iClEHiwcJacFkgQKhkci8A/Ly3Z4JJ3b4Pgw==", + "dev": true, + "dependencies": { + "unplugin": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true + }, + "node_modules/@storybook/icons": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.2.9.tgz", + "integrity": "sha512-cOmylsz25SYXaJL/gvTk/dl3pyk7yBFRfeXTsHvTA3dfhoU/LWSq0NKL9nM7WBasJyn6XPSGnLS4RtKXLw5EUg==", + "dev": true, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/instrumenter": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.2.2.tgz", + "integrity": "sha512-refwnHqKHhya45MgqakhMG0jKhTiEIAl0aOwAaQy9+zf9ncMIYQAXRQsSZ2Z188lFWE24wbeHKteb62a5ZfWwQ==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@vitest/utils": "^1.3.1", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/preset-react-webpack": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-8.2.3.tgz", + "integrity": "sha512-i886+vCMGlpFgOAOIg6BxSHgt38MXS6gqNX8Z65KVVIlI6i/9WqEQeHYfukbdGvVZ96cYWmdrnqUieIIkdCdBw==", + "dev": true, + "dependencies": { + "@storybook/core-webpack": "8.2.3", + "@storybook/react": "8.2.3", + "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.0c3f3b7.0", + "@types/node": "^18.0.0", + "@types/semver": "^7.3.4", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "magic-string": "^0.30.5", + "react-docgen": "^7.0.0", + "resolve": "^1.22.8", + "semver": "^7.3.7", + "tsconfig-paths": "^4.2.0", + "webpack": "5" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.3" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.2.3.tgz", + "integrity": "sha512-818F6pJWFBiwG0r6DiUVrV+qndwbIso2gtgJoituBgIJO2eIzNmkPNSsckbaR7u+FpE4dWiIIhmDVZSnRwvDlA==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/react-dom-shim": "8.2.3", + "@types/escodegen": "^0.0.6", + "@types/estree": "^0.0.51", + "@types/node": "^18.0.0", + "acorn": "^7.4.1", + "acorn-jsx": "^5.3.1", + "acorn-walk": "^7.2.0", + "escodegen": "^2.1.0", + "html-tags": "^3.1.0", + "lodash": "^4.17.21", + "prop-types": "^15.7.2", + "react-element-to-jsx-string": "^15.0.0", + "semver": "^7.3.7", + "ts-dedent": "^2.0.0", + "type-fest": "~2.19", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.3", + "typescript": ">= 4.2.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin": { + "version": "1.0.6--canary.9.0c3f3b7.0", + "resolved": "https://registry.npmjs.org/@storybook/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-1.0.6--canary.9.0c3f3b7.0.tgz", + "integrity": "sha512-KUqXC3oa9JuQ0kZJLBhVdS4lOneKTOopnNBK4tUAgoxWQ3u/IjzdueZjFr7gyBrXMoU6duutk3RQR9u8ZpYJ4Q==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "endent": "^2.0.1", + "find-cache-dir": "^3.3.1", + "flat-cache": "^3.0.4", + "micromatch": "^4.0.2", + "react-docgen-typescript": "^2.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "typescript": ">= 4.x", + "webpack": ">= 4" + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@storybook/react-dom-shim": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.2.2.tgz", + "integrity": "sha512-4fb1/yT9WXHzHjs0In6orIEZxga5eXd9UaXEFGudBgowCjDUVP9LabDdKTbGusz20lfaAkATsRG/W+EcSLoh8w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/react-webpack5": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/react-webpack5/-/react-webpack5-8.2.3.tgz", + "integrity": "sha512-lcm73r8S5Uy2ENuFDSR07fW+KRSYGNcrF53VItP+rgFZHrOm7gaeebrjSIA6r4tQwdd9218VaqpQGFrKAURS2w==", + "dev": true, + "dependencies": { + "@storybook/builder-webpack5": "8.2.3", + "@storybook/preset-react-webpack": "8.2.3", + "@storybook/react": "8.2.3", + "@types/node": "^18.0.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.3", + "typescript": ">= 4.2.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-webpack5/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/react/node_modules/@storybook/react-dom-shim": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.2.3.tgz", + "integrity": "sha512-N8AsM6N1S867GGWt2J2q5oY5ryqxohh3y1HqNtjg+wXf5+RkTD6M2Cgqe6p+JHz81nDKyvvVzP60MvvDhY5VOA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.3" + } + }, + "node_modules/@storybook/react/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@storybook/react/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/react/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@storybook/test": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.2.2.tgz", + "integrity": "sha512-X2qAKErjTh1X7XLAZqCMtU0ZK8JuwdKmgiqU0oXWxIDmCX6/Dm9ZIcdMZHs/S+K/UnIByjNlQpTShLVfRUeN1w==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@storybook/instrumenter": "8.2.2", + "@testing-library/dom": "10.1.0", + "@testing-library/jest-dom": "6.4.5", + "@testing-library/user-event": "14.5.2", + "@vitest/expect": "1.6.0", + "@vitest/spy": "1.6.0", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@swc/core": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.6.tgz", + "integrity": "sha512-FZxyao9eQks1MRmUshgsZTmlg/HB2oXK5fghkoWJm/1CU2q2kaJlVDll2as5j+rmWiwkp0Gidlq8wlXcEEAO+g==", + "hasInstallScript": true, + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.12" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.7.6", + "@swc/core-darwin-x64": "1.7.6", + "@swc/core-linux-arm-gnueabihf": "1.7.6", + "@swc/core-linux-arm64-gnu": "1.7.6", + "@swc/core-linux-arm64-musl": "1.7.6", + "@swc/core-linux-x64-gnu": "1.7.6", + "@swc/core-linux-x64-musl": "1.7.6", + "@swc/core-win32-arm64-msvc": "1.7.6", + "@swc/core-win32-ia32-msvc": "1.7.6", + "@swc/core-win32-x64-msvc": "1.7.6" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.6.tgz", + "integrity": "sha512-6lYHey84ZzsdtC7UuPheM4Rm0Inzxm6Sb8U6dmKc4eCx8JL0LfWG4LC5RsdsrTxnjTsbriWlnhZBffh8ijUHIQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" + }, + "node_modules/@swc/types": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz", + "integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.1.0.tgz", + "integrity": "sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz", + "integrity": "sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.3.2", + "@babel/runtime": "^7.9.2", + "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" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "@jest/globals": ">= 28", + "@types/bun": "latest", + "@types/jest": ">= 28", + "jest": ">= 28", + "vitest": ">= 0.32" + }, + "peerDependenciesMeta": { + "@jest/globals": { + "optional": true + }, + "@types/bun": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "jest": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true + }, + "node_modules/@testing-library/jest-dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", + "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", + "dev": true, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/doctrine": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", + "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", + "dev": true + }, + "node_modules/@types/emscripten": { + "version": "1.39.13", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.13.tgz", + "integrity": "sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==", + "dev": true + }, + "node_modules/@types/escodegen": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.6.tgz", + "integrity": "sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==", + "dev": true + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz", + "integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==", + "dev": true + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", + "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", + "dev": true + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz", + "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/type-utils": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz", + "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz", + "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz", + "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz", + "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz", + "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz", + "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitest/expect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", + "dev": true, + "dependencies": { + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", + "dev": true, + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@vitest/utils/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@vitest/utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/fslib": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@yarnpkg/fslib/-/fslib-2.10.3.tgz", + "integrity": "sha512-41H+Ga78xT9sHvWLlFOZLIhtU6mTGZ20pZ29EiZa97vnxdohJD2AF42rCoAoWfqUz486xY6fhjMH+DYEM9r14A==", + "dev": true, + "dependencies": { + "@yarnpkg/libzip": "^2.3.0", + "tslib": "^1.13.0" + }, + "engines": { + "node": ">=12 <14 || 14.2 - 14.9 || >14.10.0" + } + }, + "node_modules/@yarnpkg/fslib/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@yarnpkg/libzip": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/libzip/-/libzip-2.3.0.tgz", + "integrity": "sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==", + "dev": true, + "dependencies": { + "@types/emscripten": "^1.39.6", + "tslib": "^1.13.0" + }, + "engines": { + "node": ">=12 <14 || 14.2 - 14.9 || >14.10.0" + } + }, + "node_modules/@yarnpkg/libzip/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", + "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "dev": true, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", + "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-assert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", + "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001642", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", + "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chromatic": { + "version": "11.5.5", + "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-11.5.5.tgz", + "integrity": "sha512-YS0GJwegF0vpMbwZE68/xJlI4SlUGMqI78V2ATAF19YwTHaq8jGP1CPQGKUSlgWUhzPtyu3ELy6Dvv/owYljAg==", + "dev": true, + "bin": { + "chroma": "dist/bin.js", + "chromatic": "dist/bin.js", + "chromatic-cli": "dist/bin.js" + }, + "peerDependencies": { + "@chromatic-com/cypress": "^0.*.* || ^1.0.0", + "@chromatic-com/playwright": "^0.*.* || ^1.0.0" + }, + "peerDependenciesMeta": { + "@chromatic-com/cypress": { + "optional": true + }, + "@chromatic-com/playwright": { + "optional": true + } + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "dev": true, + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "dev": true + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/confbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", + "dev": true + }, + "node_modules/consola": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", + "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "dev": true, + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-js-compat": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.827", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.827.tgz", + "integrity": "sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/endent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/endent/-/endent-2.1.0.tgz", + "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==", + "dev": true, + "dependencies": { + "dedent": "^0.7.0", + "fast-json-parse": "^1.0.3", + "objectorarray": "^1.0.5" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", + "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" + } + }, + "node_modules/esbuild-register": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.5.0.tgz", + "integrity": "sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/esbuild-register/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild-register/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.8.0.tgz", + "integrity": "sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.8.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", + "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", + "dev": true, + "dependencies": { + "aria-query": "~5.1.3", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.9.1", + "axobject-query": "~3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.19", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.4.tgz", + "integrity": "sha512-Np+jo9bUwJNxCsT12pXtrGhJgT3T44T1sHhn1Ssr42XFn8TES0267wPGo5nNrMHi8qkyimDAX2BUmkf9pSaVzA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-storybook": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.8.0.tgz", + "integrity": "sha512-CZeVO5EzmPY7qghO2t64oaFM+8FTaD4uzOEjHKp516exyTKo+skKAL9GI3QALS2BXhyALJjNtwbmr1XinGE8bA==", + "dev": true, + "dependencies": { + "@storybook/csf": "^0.0.1", + "@typescript-eslint/utils": "^5.62.0", + "requireindex": "^1.2.0", + "ts-dedent": "^2.2.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "eslint": ">=6" + } + }, + "node_modules/eslint-plugin-storybook/node_modules/@storybook/csf": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", + "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-package-json": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-1.2.0.tgz", + "integrity": "sha512-45LSPmWf+gC5tdCQMNH4s9Sr00bIkiD9aN7dc5hqkrEw1geRYyDQS1v1oMHAW3ysfxfndqGsrDREHHjNNbKUfA==", + "dev": true, + "dependencies": { + "walk-up-path": "^3.0.1" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-entry-cache/node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/filesize": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.4.tgz", + "integrity": "sha512-ryBwPIIeErmxgPnm6cbESAzXjuEFubs+yKYLBZvg3CaiNcmkJChoOGcBSrZ6IwkMwPABwPpVXE6IlNdGJJrvEg==", + "dev": true, + "engines": { + "node": ">= 10.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/flat-cache/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flat-cache/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/flow-parser": { + "version": "0.239.1", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.239.1.tgz", + "integrity": "sha512-topOrETNxJ6T2gAnQiWqAlzGPj8uI2wtmNOlDIMNB+qyvGJZ6R++STbUOTAYmvPhOMz2gXnXPH0hOvURYmrBow==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", + "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/giget": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.3.tgz", + "integrity": "sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==", + "dev": true, + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.2.3", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.3", + "nypm": "^0.3.8", + "ohash": "^1.1.3", + "pathe": "^1.1.2", + "tar": "^6.2.0" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "dev": true + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", + "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-heading-rank": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", + "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.0.tgz", + "integrity": "sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jscodeshift": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.15.2.tgz", + "integrity": "sha512-FquR7Okgmc4Sd0aEDwqho3rEiKR3BdvuG9jfdHjLJ6JQoWSMpavug3AoIfnfWhxFlf+5pzQh8qjqz0DWFrNQzA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.0", + "@babel/parser": "^7.23.0", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.23.0", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", + "@babel/plugin-transform-optional-chaining": "^7.23.0", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/preset-flow": "^7.22.15", + "@babel/preset-typescript": "^7.23.0", + "@babel/register": "^7.22.15", + "babel-core": "^7.0.0-bridge.0", + "chalk": "^4.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.23.3", + "temp": "^0.8.4", + "write-file-atomic": "^2.3.0" + }, + "bin": { + "jscodeshift": "bin/jscodeshift.js" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + }, + "peerDependenciesMeta": { + "@babel/preset-env": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lottie-react": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/lottie-react/-/lottie-react-2.4.0.tgz", + "integrity": "sha512-pDJGj+AQlnlyHvOHFK7vLdsDcvbuqvwPZdMlJ360wrzGFurXeKPr8SiRCjLf3LrNYKANQtSsh5dz9UYQHuqx4w==", + "dependencies": { + "lottie-web": "^5.10.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/lottie-web": { + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", + "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==" + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/map-or-similar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", + "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", + "dev": true + }, + "node_modules/markdown-to-jsx": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.4.7.tgz", + "integrity": "sha512-0+ls1IQZdU6cwM1yu0ZjjiVWYtkbExSyUIFU2ZeDIFuZM1W42Mh4OlJ4nb4apX4H8smxDHRdFaoIVJGwfv5hkg==", + "dev": true, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memoizerific": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", + "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", + "dev": true, + "dependencies": { + "map-or-similar": "^1.5.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mlly": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", + "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/mylas": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/mylas/-/mylas-2.1.13.tgz", + "integrity": "sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/raouldeheer" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true + }, + "node_modules/node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.10.5" + } + }, + "node_modules/node-dir/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/node-dir/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.4.tgz", + "integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nypm": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.9.tgz", + "integrity": "sha512-BI2SdqqTHg2d4wJh8P9A1W+bslg33vOE9IZDY6eR2QC+Pu1iNBVZUqczrd43rJb+fMzHU7ltAYKsEFY/kHMFcw==", + "dev": true, + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.2.3", + "execa": "^8.0.1", + "pathe": "^1.1.2", + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/nypm/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/nypm/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/nypm/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nypm/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/objectorarray": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz", + "integrity": "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==", + "dev": true + }, + "node_modules/ohash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.3.tgz", + "integrity": "sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-types": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.3.tgz", + "integrity": "sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==", + "dev": true, + "dependencies": { + "confbox": "^0.1.7", + "mlly": "^1.7.1", + "pathe": "^1.1.2" + } + }, + "node_modules/plimit-lit": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/plimit-lit/-/plimit-lit-1.6.1.tgz", + "integrity": "sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==", + "dev": true, + "dependencies": { + "queue-lit": "^1.5.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/polished": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", + "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-lit": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/queue-lit/-/queue-lit-1.5.2.tgz", + "integrity": "sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-colorful": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", + "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", + "dev": true, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-confetti": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz", + "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==", + "dev": true, + "dependencies": { + "tween-functions": "^1.2.0" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.1 || ^18.0.0" + } + }, + "node_modules/react-docgen": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-7.0.3.tgz", + "integrity": "sha512-i8aF1nyKInZnANZ4uZrH49qn1paRgBZ7wZiCNBMnenlPzEv0mRl+ShpTVEI6wZNl8sSc79xZkivtgLKQArcanQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.18.9", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "@types/babel__core": "^7.18.0", + "@types/babel__traverse": "^7.18.0", + "@types/doctrine": "^0.0.9", + "@types/resolve": "^1.20.2", + "doctrine": "^3.0.0", + "resolve": "^1.22.1", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/react-docgen-typescript": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz", + "integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==", + "dev": true, + "peerDependencies": { + "typescript": ">= 4.3.x" + } + }, + "node_modules/react-docgen/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-element-to-jsx-string": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", + "integrity": "sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==", + "dev": true, + "dependencies": { + "@base2/pretty-print-object": "1.0.1", + "is-plain-object": "5.0.0", + "react-is": "18.1.0" + }, + "peerDependencies": { + "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", + "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0" + } + }, + "node_modules/react-element-to-jsx-string/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-element-to-jsx-string/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/react-inspector": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.2.tgz", + "integrity": "sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==", + "dev": true, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-router": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.1.tgz", + "integrity": "sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg==", + "dependencies": { + "@remix-run/router": "1.17.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.1.tgz", + "integrity": "sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg==", + "dependencies": { + "@remix-run/router": "1.17.1", + "react-router": "6.24.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recast": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.9.tgz", + "integrity": "sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==", + "dev": true, + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/rehype-external-links": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", + "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-is-element": "^3.0.0", + "is-absolute-url": "^4.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", + "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "github-slugger": "^2.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true, + "engines": { + "node": ">=0.10.5" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/storybook": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.2.2.tgz", + "integrity": "sha512-xDT9gyzAEFQNeK7P+Mj/8bNzN+fbm6/4D6ihdSzmczayjydpNjMs74HDHMY6S4Bfu6tRVyEK2ALPGnr6ZVofBA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/types": "^7.24.0", + "@storybook/codemod": "8.2.2", + "@storybook/core": "8.2.2", + "@types/semver": "^7.3.4", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "commander": "^6.2.1", + "cross-spawn": "^7.0.3", + "detect-indent": "^6.1.0", + "envinfo": "^7.7.3", + "execa": "^5.0.0", + "fd-package-json": "^1.2.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "giget": "^1.0.0", + "globby": "^14.0.1", + "jscodeshift": "^0.15.1", + "leven": "^3.1.0", + "ora": "^5.4.1", + "prettier": "^3.1.1", + "prompts": "^2.4.0", + "semver": "^7.3.7", + "strip-json-comments": "^3.0.1", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0" + }, + "bin": { + "getstorybook": "bin/index.cjs", + "sb": "bin/index.cjs", + "storybook": "bin/index.cjs" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/storybook-addon-react-router-v6": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/storybook-addon-react-router-v6/-/storybook-addon-react-router-v6-2.0.15.tgz", + "integrity": "sha512-4vOYIQwehlQLyXaCT9K0Iu0po2Z+pANGsqkfm/BQuAEjE9MoN7vrsrQLHINhKbmQVtNMmuS/oBR3GGNbqQ1gew==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "compare-versions": "^6.0.0", + "react-inspector": "6.0.2" + }, + "peerDependencies": { + "@storybook/blocks": "^7.0.0", + "@storybook/channels": "^7.0.0", + "@storybook/components": "^7.0.0", + "@storybook/core-events": "^7.0.0", + "@storybook/manager-api": "^7.0.0", + "@storybook/preview-api": "^7.0.0", + "@storybook/theming": "^7.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-router-dom": "^6.4.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/storybook/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/storybook/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/storybook/node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", + "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", + "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/svgo/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/swc-loader": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz", + "integrity": "sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==", + "dependencies": { + "@swc/counter": "^0.1.3" + }, + "peerDependencies": { + "@swc/core": "^1.2.147", + "webpack": ">=2" + } + }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/telejson": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-7.2.0.tgz", + "integrity": "sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==", + "dev": true, + "dependencies": { + "memoizerific": "^1.11.3" + } + }, + "node_modules/temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "dev": true, + "dependencies": { + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/temp/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/temp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/temp/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/tempy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz", + "integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==", + "dev": true, + "dependencies": { + "is-stream": "^3.0.0", + "temp-dir": "^3.0.0", + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.31.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", + "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, + "engines": { + "node": ">=6.10" + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tsc-alias": { + "version": "1.8.10", + "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.10.tgz", + "integrity": "sha512-Ibv4KAWfFkFdKJxnWfVtdOmB0Zi1RJVxcbPGiCDsFpCQSsmpWyuzHG3rQyI5YkobWwxFPEyQfu1hdo4qLG2zPw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.3", + "commander": "^9.0.0", + "globby": "^11.0.4", + "mylas": "^2.1.9", + "normalize-path": "^3.0.0", + "plimit-lit": "^1.2.6" + }, + "bin": { + "tsc-alias": "dist/bin/index.js" + } + }, + "node_modules/tsc-alias/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tween-functions": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", + "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz", + "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "7.16.0", + "@typescript-eslint/parser": "7.16.0", + "@typescript-eslint/utils": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/ufo": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", + "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unplugin": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.11.0.tgz", + "integrity": "sha512-3r7VWZ/webh0SGgJScpWl2/MRCZK5d3ZYFcNaeci/GQ7Teop7zf0Nl2pUuz7G21BwPd9pcUPOC5KmJ2L3WgC5g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "chokidar": "^3.6.0", + "webpack-sources": "^3.2.3", + "webpack-virtual-modules": "^0.6.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", + "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", + "dev": true, + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.11.2" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, + "node_modules/url/node_modules/qs": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.3.tgz", + "integrity": "sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walk-up-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", + "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", + "dev": true + }, + "node_modules/watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webpack": { + "version": "5.93.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", + "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-hot-middleware": { + "version": "2.26.1", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.26.1.tgz", + "integrity": "sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==", + "dev": true, + "dependencies": { + "ansi-html-community": "0.0.8", + "html-entities": "^2.1.0", + "strip-ansi": "^6.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "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 + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/HDesign/package.json b/HDesign/package.json new file mode 100644 index 000000000..062987bf1 --- /dev/null +++ b/HDesign/package.json @@ -0,0 +1,72 @@ +{ + "name": "haengdong-design", + "version": "0.1.81", + "description": "", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "start": "webpack serve ", + "build": "rm -rf dist && mkdir dist && tsc && cp -r ./src/assets ./dist && tsc-alias", + "storybook": "storybook dev -p 6006", + "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", + "format": "prettier --write {src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'", + "build-storybook": "storybook build" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@chromatic-com/storybook": "^1.6.1", + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", + "@storybook/addon-essentials": "^8.2.2", + "@storybook/addon-interactions": "^8.2.2", + "@storybook/addon-links": "^8.2.2", + "@storybook/addon-onboarding": "^8.2.2", + "@storybook/blocks": "^8.2.2", + "@storybook/react": "^8.2.2", + "@storybook/react-webpack5": "^8.2.3", + "@storybook/test": "^8.2.2", + "@swc/core": "^1.7.6", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "esbuild": "^0.23.0", + "eslint": "^9.8.0", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.4", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-storybook": "^0.8.0", + "file-loader": "^6.2.0", + "globals": "^15.8.0", + "prettier": "3.3.2", + "storybook": "^8.2.2", + "storybook-addon-react-router-v6": "^2.0.15", + "ts-loader": "^9.5.1", + "tsc-alias": "^1.8.10", + "typescript": "^5.5.3", + "typescript-eslint": "^7.16.0" + }, + "dependencies": { + "@emotion/react": "^11.11.4", + "@storybook/addon-webpack5-compiler-swc": "^1.0.5", + "@svgr/webpack": "^8.1.0", + "lottie-react": "^2.4.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "engines": { + "npm": ">=10.7.0", + "node": ">=20.15.1" + } +} diff --git a/client/src/assets/image/buljusa.svg b/HDesign/src/assets/buljusa.svg similarity index 100% rename from client/src/assets/image/buljusa.svg rename to HDesign/src/assets/buljusa.svg diff --git a/client/src/assets/image/confirm.svg b/HDesign/src/assets/confirm.svg similarity index 100% rename from client/src/assets/image/confirm.svg rename to HDesign/src/assets/confirm.svg diff --git a/client/src/assets/image/error.svg b/HDesign/src/assets/error.svg similarity index 100% rename from client/src/assets/image/error.svg rename to HDesign/src/assets/error.svg diff --git a/HDesign/src/assets/index.ts b/HDesign/src/assets/index.ts new file mode 100644 index 000000000..a9c277581 --- /dev/null +++ b/HDesign/src/assets/index.ts @@ -0,0 +1,7 @@ +export {default as InputDelete} from '@assets/inputDelete.svg'; +export {default as Buljusa} from '@assets/buljusa.svg'; +export {default as Error} from '@assets/error.svg'; +export {default as Confirm} from '@assets/confirm.svg'; +export {default as Trash} from '@assets/trash.svg'; +export {default as Search} from '@assets/search.svg'; +export {default as RightChevron} from '@assets/rightChevron.svg'; diff --git a/client/src/assets/image/inputDelete.svg b/HDesign/src/assets/inputDelete.svg similarity index 100% rename from client/src/assets/image/inputDelete.svg rename to HDesign/src/assets/inputDelete.svg diff --git a/client/src/assets/image/loadingAnimation.json b/HDesign/src/assets/loadingAnimation.json similarity index 100% rename from client/src/assets/image/loadingAnimation.json rename to HDesign/src/assets/loadingAnimation.json diff --git a/client/src/assets/image/rightChevron.svg b/HDesign/src/assets/rightChevron.svg similarity index 100% rename from client/src/assets/image/rightChevron.svg rename to HDesign/src/assets/rightChevron.svg diff --git a/client/src/assets/image/search.svg b/HDesign/src/assets/search.svg similarity index 100% rename from client/src/assets/image/search.svg rename to HDesign/src/assets/search.svg diff --git a/HDesign/src/assets/svg.d.ts b/HDesign/src/assets/svg.d.ts new file mode 100644 index 000000000..2db81e756 --- /dev/null +++ b/HDesign/src/assets/svg.d.ts @@ -0,0 +1,6 @@ +declare module '*.svg' { + import type React from 'react'; + + const SVG: React.FC>; + export default SVG; +} diff --git a/client/src/assets/image/trash.svg b/HDesign/src/assets/trash.svg similarity index 100% rename from client/src/assets/image/trash.svg rename to HDesign/src/assets/trash.svg diff --git a/client/src/components/Design/components/BottomSheet/BottomSheet.stories.tsx b/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx similarity index 86% rename from client/src/components/Design/components/BottomSheet/BottomSheet.stories.tsx rename to HDesign/src/components/BottomSheet/BottomSheet.stories.tsx index 107f96c1f..67d4cdb37 100644 --- a/client/src/components/Design/components/BottomSheet/BottomSheet.stories.tsx +++ b/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx @@ -3,8 +3,8 @@ import type {Meta, StoryObj} from '@storybook/react'; import {useState} from 'react'; -import Button from '@HDcomponents/Button/Button'; -import BottomSheet from '@HDcomponents/BottomSheet/BottomSheet'; +import Button from '@components/Button/Button'; +import BottomSheet from '@components/BottomSheet/BottomSheet'; const meta = { title: 'Components/BottomSheet', diff --git a/client/src/components/Design/components/BottomSheet/BottomSheet.style.ts b/HDesign/src/components/BottomSheet/BottomSheet.style.ts similarity index 94% rename from client/src/components/Design/components/BottomSheet/BottomSheet.style.ts rename to HDesign/src/components/BottomSheet/BottomSheet.style.ts index a15a1a959..08c373835 100644 --- a/client/src/components/Design/components/BottomSheet/BottomSheet.style.ts +++ b/HDesign/src/components/BottomSheet/BottomSheet.style.ts @@ -10,7 +10,7 @@ export const display = (visible: boolean) => export const dimmedLayerStyle = (theme: Theme, isOpened: boolean) => css({ position: 'fixed', - zIndex: theme.zIndex.bottomSheetDimmedLayer, + zIndex: '30', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', @@ -31,7 +31,7 @@ export const bottomSheetContainerStyle = (theme: Theme, isOpened: boolean, isDra flexDirection: 'column', alignItems: 'center', gap: '1.5rem', - zIndex: theme.zIndex.bottomSheetContainer, + zIndex: '50', inset: 'auto 0 0 50%', maxWidth: '768px', width: '100%', diff --git a/client/src/components/Design/components/BottomSheet/BottomSheet.tsx b/HDesign/src/components/BottomSheet/BottomSheet.tsx similarity index 94% rename from client/src/components/Design/components/BottomSheet/BottomSheet.tsx rename to HDesign/src/components/BottomSheet/BottomSheet.tsx index 48d388625..3ffadc323 100644 --- a/client/src/components/Design/components/BottomSheet/BottomSheet.tsx +++ b/HDesign/src/components/BottomSheet/BottomSheet.tsx @@ -1,10 +1,11 @@ /** @jsxImportSource @emotion/react */ import {createPortal} from 'react-dom'; +import {BottomSheetProps} from '@components/BottomSheet/BottomSheet.type'; + import {useTheme} from '@theme/HDesignProvider'; import {useBottomSheet} from './useBottomSheet'; -import {BottomSheetProps} from './BottomSheet.type'; import { bottomSheetContainerStyle, dimmedLayerStyle, diff --git a/client/src/components/Design/components/BottomSheet/BottomSheet.type.ts b/HDesign/src/components/BottomSheet/BottomSheet.type.ts similarity index 100% rename from client/src/components/Design/components/BottomSheet/BottomSheet.type.ts rename to HDesign/src/components/BottomSheet/BottomSheet.type.ts diff --git a/client/src/components/Design/components/BottomSheet/useBottomSheet.ts b/HDesign/src/components/BottomSheet/useBottomSheet.ts similarity index 99% rename from client/src/components/Design/components/BottomSheet/useBottomSheet.ts rename to HDesign/src/components/BottomSheet/useBottomSheet.ts index e9a901c14..3e2564550 100644 --- a/client/src/components/Design/components/BottomSheet/useBottomSheet.ts +++ b/HDesign/src/components/BottomSheet/useBottomSheet.ts @@ -22,8 +22,6 @@ export const useBottomSheet = ({isOpened, onClose, onOpen}: UseBottomSheetProps) return () => clearTimeout(timer); } - - return; }, [opened]); useEffect(() => { diff --git a/client/src/components/Design/components/Button/Button.stories.tsx b/HDesign/src/components/Button/Button.stories.tsx similarity index 100% rename from client/src/components/Design/components/Button/Button.stories.tsx rename to HDesign/src/components/Button/Button.stories.tsx diff --git a/client/src/components/Design/components/Button/Button.style.ts b/HDesign/src/components/Button/Button.style.ts similarity index 94% rename from client/src/components/Design/components/Button/Button.style.ts rename to HDesign/src/components/Button/Button.style.ts index 0d274f116..24c46ec5b 100644 --- a/client/src/components/Design/components/Button/Button.style.ts +++ b/HDesign/src/components/Button/Button.style.ts @@ -1,7 +1,8 @@ import {css} from '@emotion/react'; -import {setDarker, setEmphasize, setLighter} from '@HDutils/colors'; -import {Theme} from '@theme/theme.type'; +import {setDarker, setEmphasize, setLighter} from '@utils/colors'; + +import {Theme} from '../../theme/theme.type'; import {ButtonStyleProps, ButtonSize, ButtonVariants} from './Button.type'; @@ -23,7 +24,7 @@ const getButtonDefaultStyle = (theme: Theme) => whiteSpace: 'nowrap', '&:disabled': { - backgroundColor: theme.colors.grayContainer, + backgroundColor: theme.colors.tertiary, color: theme.colors.onPrimary, cursor: 'default', }, diff --git a/client/src/components/Design/components/Button/Button.tsx b/HDesign/src/components/Button/Button.tsx similarity index 83% rename from client/src/components/Design/components/Button/Button.tsx rename to HDesign/src/components/Button/Button.tsx index 3b8896a1c..f0277590b 100644 --- a/client/src/components/Design/components/Button/Button.tsx +++ b/HDesign/src/components/Button/Button.tsx @@ -3,11 +3,12 @@ import React, {forwardRef} from 'react'; import Lottie from 'lottie-react'; -import loadingAnimation from '@assets/image/loadingAnimation.json'; -import {useTheme} from '@theme/HDesignProvider'; +import {buttonStyle} from '@components/Button/Button.style'; +import {ButtonProps, ButtonSize} from '@components/Button/Button.type'; + +import loadingAnimation from '@assets/loadingAnimation.json'; -import {ButtonProps, ButtonSize} from './Button.type'; -import {buttonStyle} from './Button.style'; +import {useTheme} from '@theme/HDesignProvider'; const animationSize = (size: ButtonSize) => { switch (size) { diff --git a/client/src/components/Design/components/Button/Button.type.ts b/HDesign/src/components/Button/Button.type.ts similarity index 100% rename from client/src/components/Design/components/Button/Button.type.ts rename to HDesign/src/components/Button/Button.type.ts diff --git a/client/src/components/Design/components/DragHandleItem/DragHandleItem.stories.tsx b/HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx similarity index 94% rename from client/src/components/Design/components/DragHandleItem/DragHandleItem.stories.tsx rename to HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx index 8043777b5..c7125d4d8 100644 --- a/client/src/components/Design/components/DragHandleItem/DragHandleItem.stories.tsx +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx @@ -1,6 +1,6 @@ import type {Meta, StoryObj} from '@storybook/react'; -import DragHandleItem from '@HDcomponents/DragHandleItem/DragHandleItem'; +import DragHandleItem from '@components/DragHandleItem/DragHandleItem'; const meta = { title: 'Components/DragHandleItem', diff --git a/client/src/components/Design/components/DragHandleItem/DragHandleItem.style.ts b/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts similarity index 99% rename from client/src/components/Design/components/DragHandleItem/DragHandleItem.style.ts rename to HDesign/src/components/DragHandleItem/DragHandleItem.style.ts index 7136e7b3c..b641c5fb3 100644 --- a/client/src/components/Design/components/DragHandleItem/DragHandleItem.style.ts +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts @@ -1,6 +1,7 @@ import {css} from '@emotion/react'; import {Theme} from '@theme/theme.type'; + import {ColorKeys} from '@token/colors'; export const dragHandleItemStyle = (theme: Theme, hasDragHandle: boolean, backgroundColor: ColorKeys) => diff --git a/client/src/components/Design/components/DragHandleItem/DragHandleItem.tsx b/HDesign/src/components/DragHandleItem/DragHandleItem.tsx similarity index 85% rename from client/src/components/Design/components/DragHandleItem/DragHandleItem.tsx rename to HDesign/src/components/DragHandleItem/DragHandleItem.tsx index 4cca73a4f..9acf38084 100644 --- a/client/src/components/Design/components/DragHandleItem/DragHandleItem.tsx +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.tsx @@ -1,8 +1,9 @@ /** @jsxImportSource @emotion/react */ -import Icon from '@HDcomponents/Icon/Icon'; -import Flex from '@HDcomponents/Flex/Flex'; -import Text from '@HDcomponents/Text/Text'; -import IsFixedIcon from '@HDcomponents/IsFixedIcon/IsFixedIcon'; +import Icon from '@components/Icon/Icon'; +import Flex from '@components/Flex/Flex'; +import Text from '@components/Text/Text'; +import IsFixedIcon from '@components/IsFixedIcon/IsFixedIcon'; + import {useTheme} from '@theme/HDesignProvider'; import IconButton from '../IconButton/IconButton'; diff --git a/client/src/components/Design/components/DragHandleItem/DragHandleItem.type.ts b/HDesign/src/components/DragHandleItem/DragHandleItem.type.ts similarity index 99% rename from client/src/components/Design/components/DragHandleItem/DragHandleItem.type.ts rename to HDesign/src/components/DragHandleItem/DragHandleItem.type.ts index 8b62dd374..fc0a1f520 100644 --- a/client/src/components/Design/components/DragHandleItem/DragHandleItem.type.ts +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.type.ts @@ -1,4 +1,5 @@ import {Theme} from '@theme/theme.type'; + import {ColorKeys} from '@token/colors'; export interface DragHandleItemStyleProps { diff --git a/client/src/components/Design/components/DragHandleItemContainer/DragHandleItemContainer.stories.tsx b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.stories.tsx similarity index 92% rename from client/src/components/Design/components/DragHandleItemContainer/DragHandleItemContainer.stories.tsx rename to HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.stories.tsx index 1e215ca9d..46c3db8a2 100644 --- a/client/src/components/Design/components/DragHandleItemContainer/DragHandleItemContainer.stories.tsx +++ b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.stories.tsx @@ -1,8 +1,8 @@ /** @jsxImportSource @emotion/react */ import type {Meta, StoryObj} from '@storybook/react'; -import DragHandleItemContainer from '@HDcomponents/DragHandleItemContainer/DragHandleItemContainer'; -import DragHandleItem from '@HDcomponents/DragHandleItem/DragHandleItem'; +import DragHandleItemContainer from '@components/DragHandleItemContainer/DragHandleItemContainer'; +import DragHandleItem from '@components/DragHandleItem/DragHandleItem'; const meta = { title: 'Components/DragHandleItemContainer', diff --git a/client/src/components/Design/components/DragHandleItemContainer/DragHandleItemContainer.style.ts b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.style.ts similarity index 99% rename from client/src/components/Design/components/DragHandleItemContainer/DragHandleItemContainer.style.ts rename to HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.style.ts index db2ada615..b5bab9422 100644 --- a/client/src/components/Design/components/DragHandleItemContainer/DragHandleItemContainer.style.ts +++ b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.style.ts @@ -1,6 +1,7 @@ import {css} from '@emotion/react'; import {Theme} from '@theme/theme.type'; + import {ColorKeys} from '@token/colors'; export const containerStyle = (theme: Theme, backgroundColor: ColorKeys) => diff --git a/client/src/components/Design/components/DragHandleItemContainer/DragHandleItemContainer.tsx b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.tsx similarity index 100% rename from client/src/components/Design/components/DragHandleItemContainer/DragHandleItemContainer.tsx rename to HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.tsx diff --git a/client/src/components/Design/components/DragHandleItemContainer/DragHandleItemContainer.type.ts b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.type.ts similarity index 100% rename from client/src/components/Design/components/DragHandleItemContainer/DragHandleItemContainer.type.ts rename to HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.type.ts diff --git a/client/src/components/Design/components/EditableItem/EditableItem.Input.style.ts b/HDesign/src/components/EditableItem/EditableItem.Input.style.ts similarity index 97% rename from client/src/components/Design/components/EditableItem/EditableItem.Input.style.ts rename to HDesign/src/components/EditableItem/EditableItem.Input.style.ts index eeefb44ca..eadff482e 100644 --- a/client/src/components/Design/components/EditableItem/EditableItem.Input.style.ts +++ b/HDesign/src/components/EditableItem/EditableItem.Input.style.ts @@ -1,7 +1,8 @@ import {css} from '@emotion/react'; -import {TextSize} from '@HDcomponents/Text/Text.type'; +import {TextSize} from '@components/Text/Text.type'; import {WithTheme} from '@type/withTheme'; + import TYPOGRAPHY from '@token/typography'; type UnderlineProps = { diff --git a/client/src/components/Design/components/EditableItem/EditableItem.Input.tsx b/HDesign/src/components/EditableItem/EditableItem.Input.tsx similarity index 90% rename from client/src/components/Design/components/EditableItem/EditableItem.Input.tsx rename to HDesign/src/components/EditableItem/EditableItem.Input.tsx index bc7d6ca6a..c0a08bc0e 100644 --- a/client/src/components/Design/components/EditableItem/EditableItem.Input.tsx +++ b/HDesign/src/components/EditableItem/EditableItem.Input.tsx @@ -1,9 +1,10 @@ /** @jsxImportSource @emotion/react */ import {forwardRef, useEffect, useImperativeHandle, useRef} from 'react'; -import Flex from '@HDcomponents/Flex/Flex'; -import Text from '@HDcomponents/Text/Text'; -import IsFixedIcon from '@HDcomponents/IsFixedIcon/IsFixedIcon'; +import Flex from '@components/Flex/Flex'; +import Text from '@components/Text/Text'; +import IsFixedIcon from '@components/IsFixedIcon/IsFixedIcon'; + import {useTheme} from '@theme/HDesignProvider'; import {editingContainerStyle, inputStyle, inputWrapperStyle, underlineStyle} from './EditableItem.Input.style'; @@ -28,13 +29,10 @@ export const EditableItemInput = forwardRef(functi return (
- -
{htmlProps.value || htmlProps.placeholder}
- {isFixed && }
diff --git a/client/src/components/Design/components/EditableItem/EditableItem.tsx b/HDesign/src/components/EditableItem/EditableItem.tsx similarity index 93% rename from client/src/components/Design/components/EditableItem/EditableItem.tsx rename to HDesign/src/components/EditableItem/EditableItem.tsx index 97a295ccb..f8b9ca434 100644 --- a/client/src/components/Design/components/EditableItem/EditableItem.tsx +++ b/HDesign/src/components/EditableItem/EditableItem.tsx @@ -1,6 +1,7 @@ /** @jsxImportSource @emotion/react */ -import Text from '@HDcomponents/Text/Text'; -import Flex from '@HDcomponents/Flex/Flex'; +import Text from '@components/Text/Text'; +import Flex from '@components/Flex/Flex'; + import {useTheme} from '@theme/HDesignProvider'; import {editableItemStyle, labelTextStyle} from './EditableItem.style'; diff --git a/client/src/components/Design/components/EditableItem/EditableItem.type.ts b/HDesign/src/components/EditableItem/EditableItem.type.ts similarity index 99% rename from client/src/components/Design/components/EditableItem/EditableItem.type.ts rename to HDesign/src/components/EditableItem/EditableItem.type.ts index e28114308..a56835855 100644 --- a/client/src/components/Design/components/EditableItem/EditableItem.type.ts +++ b/HDesign/src/components/EditableItem/EditableItem.type.ts @@ -1,4 +1,5 @@ import {Theme} from '@theme/theme.type'; + import {ColorKeys} from '@token/colors'; export interface EditableItemStyleProps { diff --git a/client/src/components/Design/components/EditableItem/useEditableItem.ts b/HDesign/src/components/EditableItem/useEditableItem.ts similarity index 100% rename from client/src/components/Design/components/EditableItem/useEditableItem.ts rename to HDesign/src/components/EditableItem/useEditableItem.ts diff --git a/client/src/components/Design/components/EditableItem/useEditableItemInput.ts b/HDesign/src/components/EditableItem/useEditableItemInput.ts similarity index 98% rename from client/src/components/Design/components/EditableItem/useEditableItemInput.ts rename to HDesign/src/components/EditableItem/useEditableItemInput.ts index c9899a211..3253ad0ea 100644 --- a/client/src/components/Design/components/EditableItem/useEditableItemInput.ts +++ b/HDesign/src/components/EditableItem/useEditableItemInput.ts @@ -32,8 +32,6 @@ const useEditableItemInput = ({inputRef}: UseEditableItemInputProps) => { input.removeEventListener('blur', handleBlur); }; } - - return; }, [handleFocus, handleBlur, inputRef]); useEffect(() => { diff --git a/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx b/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx new file mode 100644 index 000000000..ccf8e28de --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx @@ -0,0 +1,29 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import ExpenseList from '@components/ExpenseList/ExpenseList'; + +const meta = { + title: 'Components/ExpenseList', + component: ExpenseList, + tags: ['autodocs'], + argTypes: { + expenseList: { + description: '', + }, + }, + args: { + expenseList: [ + {name: '์†Œํ•˜', price: 2000}, + {name: 'ํ† ๋‹ค๋ฆฌ', price: 2000}, + {name: '์›จ๋””', price: 1080}, + {name: '์ฟ ํ‚ค', price: 3020}, + ], + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.style.ts b/HDesign/src/components/ExpenseList/ExpenseList.style.ts new file mode 100644 index 000000000..8dbd227aa --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.style.ts @@ -0,0 +1,29 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +export const expenseItemStyle = () => + css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + width: '100%', + height: '2.5rem', + padding: '0.5rem 1rem', + }); + +export const expenseItemLeftStyle = () => + css({ + display: 'flex', + alignItems: 'center', + gap: '1rem', + }); + +export const expenseListStyle = (theme: Theme) => + css({ + width: '100%', + backgroundColor: theme.colors.white, + padding: '0.5rem 0', + borderRadius: '1rem', + height: '100%', + }); diff --git a/HDesign/src/components/ExpenseList/ExpenseList.tsx b/HDesign/src/components/ExpenseList/ExpenseList.tsx new file mode 100644 index 000000000..1f57810e5 --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.tsx @@ -0,0 +1,37 @@ +/** @jsxImportSource @emotion/react */ + +import Text from '@components/Text/Text'; +import Icon from '@components/Icon/Icon'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {ExpenseItemProps, ExpenseListProps} from './ExpenseList.type'; +import {expenseItemStyle, expenseListStyle, expenseItemLeftStyle} from './ExpenseList.style'; + +// TODO: (@soha) ๋”ฐ๋กœ ํŒŒ์ผ ๋ถ„๋ฆฌํ• ๊นŒ ๊ณ ๋ฏผ์ค‘.. ์—ฌ๊ธฐ์„œ๋งŒ ์‚ฌ์šฉํ•  ๊ฒƒ ๊ฐ™๊ธด ํ•œ๋ฐ.. ํ  +// TODO: (@todari) : ์ถ”ํ›„ ํด๋ฆญ ์‹œ ์ƒํ˜ธ์ž‘์šฉ์ด ์ƒ๊ธฐ๋ฉด iconButton์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Œ +function ExpenseItem({name, price, ...buttonProps}: ExpenseItemProps) { + const {theme} = useTheme(); + return ( + + ); +} + +function ExpenseList({expenseList = []}: ExpenseListProps) { + const {theme} = useTheme(); + return ( +
+ {expenseList.map(({name, price}, index: number) => ( + + ))} +
+ ); +} + +export default ExpenseList; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.type.ts b/HDesign/src/components/ExpenseList/ExpenseList.type.ts new file mode 100644 index 000000000..939cd2f68 --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.type.ts @@ -0,0 +1,10 @@ +export interface ExpenseItemCustomProps { + name: string; + price: number; +} + +export type ExpenseItemProps = React.ComponentProps<'button'> & ExpenseItemCustomProps; + +export type ExpenseListProps = { + expenseList: ExpenseItemProps[]; +}; diff --git a/client/src/components/Design/components/FixedButton/FixedButton.stories.tsx b/HDesign/src/components/FixedButton/FixedButton.stories.tsx similarity index 93% rename from client/src/components/Design/components/FixedButton/FixedButton.stories.tsx rename to HDesign/src/components/FixedButton/FixedButton.stories.tsx index ad5a98ee9..47485f851 100644 --- a/client/src/components/Design/components/FixedButton/FixedButton.stories.tsx +++ b/HDesign/src/components/FixedButton/FixedButton.stories.tsx @@ -1,7 +1,7 @@ /** @jsxImportSource @emotion/react */ import type {Meta, StoryObj} from '@storybook/react'; -import FixedButton from '@HDcomponents/FixedButton/FixedButton'; +import FixedButton from '@components/FixedButton/FixedButton'; const meta = { title: 'Components/FixedButton', diff --git a/client/src/components/Design/components/FixedButton/FixedButton.style.ts b/HDesign/src/components/FixedButton/FixedButton.style.ts similarity index 68% rename from client/src/components/Design/components/FixedButton/FixedButton.style.ts rename to HDesign/src/components/FixedButton/FixedButton.style.ts index 3698c2b52..2e774918d 100644 --- a/client/src/components/Design/components/FixedButton/FixedButton.style.ts +++ b/HDesign/src/components/FixedButton/FixedButton.style.ts @@ -1,9 +1,11 @@ import {css} from '@emotion/react'; -import {ButtonVariants} from '@HDcomponents/Button/Button.type'; -import {FixedButtonStyleProps} from '@HDcomponents/FixedButton/FixedButton.type'; +import {ButtonVariants} from '@components/Button/Button.type'; +import {FixedButtonStyleProps} from '@components/FixedButton/FixedButton.type'; + import {Theme} from '@theme/theme.type'; -import {setDarker, setLighter} from '@HDutils/colors'; + +import {setDarker, setLighter} from '@utils/colors'; export const fixedButtonContainerStyle = (theme: Theme) => css({ @@ -14,7 +16,6 @@ export const fixedButtonContainerStyle = (theme: Theme) => margin: '0 auto', backgroundColor: theme.colors.white, boxSizing: 'border-box', - zIndex: theme.zIndex.fixedButton, }); export const buttonContainerStyle = css({ @@ -36,62 +37,30 @@ const getHoverAndActiveBackground = (color: string) => }, }); -export const deleteButtonStyle = (theme: Theme) => +export const deleteButtonStyle = (theme: Theme) => [ css({ display: 'flex', justifyContent: 'center', - padding: '1rem 1.5rem', - borderRadius: '1rem', - width: '100%', + padding: '0.875rem 1rem', + borderRadius: '1.25rem', + backgroundColor: theme.colors.error, + color: theme.colors.white, fontFamily: 'Pretendard', - fontSize: '1.25rem', + fontSize: '1rem', fontWeight: '700', lineHeight: '1', transition: '0.2s', transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', - - backgroundColor: theme.colors.tertiary, - color: theme.colors.error, - - '&:disabled': { - backgroundColor: theme.colors.grayContainer, - color: theme.colors.onPrimary, - cursor: 'default', - }, - }); + }), + getHoverAndActiveBackground(theme.colors.error), +]; export const fixedButtonStyle = (props: Required) => { return [getFixedButtonDefaultStyle(props.theme), getFixedButtonVariantsStyle(props.variants, props.theme)]; }; -export const cancleButtonStyle = (theme: Theme) => - css({ - display: 'flex', - justifyContent: 'center', - padding: '1rem 1.5rem', - borderRadius: '1rem', - width: '100%', - - fontFamily: 'Pretendard', - fontSize: '1.25rem', - fontWeight: '700', - lineHeight: '1', - - transition: '0.2s', - transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', - - backgroundColor: theme.colors.tertiary, - color: theme.colors.onTertiary, - - '&:disabled': { - backgroundColor: theme.colors.grayContainer, - color: theme.colors.onPrimary, - cursor: 'default', - }, - }); - const getFixedButtonDefaultStyle = (theme: Theme) => css({ display: 'flex', @@ -109,7 +78,7 @@ const getFixedButtonDefaultStyle = (theme: Theme) => transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', '&:disabled': { - backgroundColor: theme.colors.grayContainer, + backgroundColor: theme.colors.tertiary, color: theme.colors.onPrimary, cursor: 'default', }, diff --git a/client/src/components/Design/components/FixedButton/FixedButton.tsx b/HDesign/src/components/FixedButton/FixedButton.tsx similarity index 55% rename from client/src/components/Design/components/FixedButton/FixedButton.tsx rename to HDesign/src/components/FixedButton/FixedButton.tsx index 28192cd33..4430016d6 100644 --- a/client/src/components/Design/components/FixedButton/FixedButton.tsx +++ b/HDesign/src/components/FixedButton/FixedButton.tsx @@ -2,21 +2,21 @@ import {forwardRef} from 'react'; import Lottie from 'lottie-react'; -import loadingAnimation from '@assets/image/loadingAnimation.json'; import { fixedButtonContainerStyle, fixedButtonStyle, buttonContainerStyle, - cancleButtonStyle, - deleteButtonStyle, -} from '@HDcomponents/FixedButton/FixedButton.style'; -import {FixedButtonProps} from '@HDcomponents/FixedButton/FixedButton.type'; -import IconButton from '@HDcomponents/IconButton/IconButton'; -import Icon from '@HDcomponents/Icon/Icon'; +} from '@components/FixedButton/FixedButton.style'; +import {FixedButtonProps} from '@components/FixedButton/FixedButton.type'; +import IconButton from '@components/IconButton/IconButton'; +import Icon from '@components/Icon/Icon'; + +import loadingAnimation from '@assets/loadingAnimation.json'; + import {useTheme} from '@theme/HDesignProvider'; export const FixedButton: React.FC = forwardRef(function Button( - {variants = 'primary', onDeleteClick, onBackClick, disabled, children, ...htmlProps}: FixedButtonProps, + {variants = 'primary', onDeleteClick, disabled, children, ...htmlProps}: FixedButtonProps, ref, ) { const {theme} = useTheme(); @@ -24,14 +24,9 @@ export const FixedButton: React.FC = forwardRef
{onDeleteClick && ( - - )} - {onBackClick && ( - + + + )} + + ))} + + + )} + + ); +}; + +export default Search; diff --git a/HDesign/src/components/Switch/Switch.stories.tsx b/HDesign/src/components/Switch/Switch.stories.tsx new file mode 100644 index 000000000..a3558754a --- /dev/null +++ b/HDesign/src/components/Switch/Switch.stories.tsx @@ -0,0 +1,35 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import Switch from '@components/Switch/Switch'; + +const meta = { + title: 'Components/Switch', + component: Switch, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + value: { + description: '', + control: {type: 'select', options: ['ํ™ˆ', '๊ด€๋ฆฌ']}, + }, + values: { + description: '', + }, + onChange: { + description: '', + }, + }, + args: { + value: 'ํ™ˆ', + values: ['ํ™ˆ', '๊ด€๋ฆฌ'], + onChange: value => alert(`${value} ์„ ํƒ๋จ`), + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Switch/Switch.style.ts b/HDesign/src/components/Switch/Switch.style.ts new file mode 100644 index 000000000..d88c18748 --- /dev/null +++ b/HDesign/src/components/Switch/Switch.style.ts @@ -0,0 +1,6 @@ +import {css} from '@emotion/react'; + +export const switchContainerStyle = css({ + display: 'flex', + gap: '0.75rem', +}); diff --git a/HDesign/src/components/Switch/Switch.tsx b/HDesign/src/components/Switch/Switch.tsx new file mode 100644 index 000000000..4a1275185 --- /dev/null +++ b/HDesign/src/components/Switch/Switch.tsx @@ -0,0 +1,24 @@ +/** @jsxImportSource @emotion/react */ +import TextButton from '../TextButton/TextButton'; + +import {switchContainerStyle} from './Switch.style'; +import {SwitchProps} from './Switch.type'; + +function Switch({value, values, onChange}: SwitchProps) { + return ( +
+ {values.map((item, index) => ( + onChange(values[index])} + > + {item} + + ))} +
+ ); +} + +export default Switch; diff --git a/HDesign/src/components/Switch/Switch.type.ts b/HDesign/src/components/Switch/Switch.type.ts new file mode 100644 index 000000000..7e0d31d0f --- /dev/null +++ b/HDesign/src/components/Switch/Switch.type.ts @@ -0,0 +1,5 @@ +export interface SwitchProps { + value: string; + values: string[]; + onChange: (value: string) => void; +} diff --git a/client/src/components/Design/components/Tabs/Tab.tsx b/HDesign/src/components/Tabs/Tab.tsx similarity index 100% rename from client/src/components/Design/components/Tabs/Tab.tsx rename to HDesign/src/components/Tabs/Tab.tsx diff --git a/client/src/components/Design/components/Tabs/Tab.type.ts b/HDesign/src/components/Tabs/Tab.type.ts similarity index 100% rename from client/src/components/Design/components/Tabs/Tab.type.ts rename to HDesign/src/components/Tabs/Tab.type.ts diff --git a/client/src/components/Design/components/Tabs/Tabs.stories.tsx b/HDesign/src/components/Tabs/Tabs.stories.tsx similarity index 93% rename from client/src/components/Design/components/Tabs/Tabs.stories.tsx rename to HDesign/src/components/Tabs/Tabs.stories.tsx index b5767e40b..a40e60b07 100644 --- a/client/src/components/Design/components/Tabs/Tabs.stories.tsx +++ b/HDesign/src/components/Tabs/Tabs.stories.tsx @@ -2,7 +2,7 @@ import type {Meta, StoryObj} from '@storybook/react'; import React from 'react'; -import Tabs from '@HDcomponents/Tabs/Tabs'; +import Tabs from '@components/Tabs/Tabs'; import Tab from './Tab'; diff --git a/HDesign/src/components/Tabs/Tabs.style.ts b/HDesign/src/components/Tabs/Tabs.style.ts new file mode 100644 index 000000000..3ea38924c --- /dev/null +++ b/HDesign/src/components/Tabs/Tabs.style.ts @@ -0,0 +1,53 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +export const tabListStyle = (theme: Theme) => + css({ + position: 'relative', + + backgroundColor: theme.colors.white, + + cursor: 'pointer', + + WebkitTapHighlightColor: 'transparent', + + '&::after': { + position: 'absolute', + left: 0, + bottom: 0, + zIndex: 1, + + width: '100%', + height: '0.0625rem', + + backgroundColor: theme.colors.gray, + + content: '""', + }, + }); + +export const tabItemStyle = css({ + flex: 1, + + textAlign: 'center', +}); + +export const tabTextStyle = (theme: Theme, selected: boolean) => + css({ + color: selected ? theme.colors.onTertiary : theme.colors.gray, + }); + +export const indicatorStyle = (theme: Theme, leftPosition: string, tabLength: number) => + css({ + position: 'absolute', + left: leftPosition, + bottom: 0, + zIndex: 2, + + width: `calc(100% / ${tabLength})`, + height: '0.125rem', + + backgroundColor: theme.colors.onSecondary, + transition: 'left 0.3s', + }); diff --git a/HDesign/src/components/Tabs/Tabs.tsx b/HDesign/src/components/Tabs/Tabs.tsx new file mode 100644 index 000000000..0245b5ba7 --- /dev/null +++ b/HDesign/src/components/Tabs/Tabs.tsx @@ -0,0 +1,53 @@ +/** @jsxImportSource @emotion/react */ +import React, {useState} from 'react'; +import {css} from '@emotion/react'; + +import {useTheme} from '@theme/HDesignProvider'; + +import Text from '../Text/Text'; +import Flex from '../Flex/Flex'; + +import {tabListStyle, indicatorStyle, tabItemStyle, tabTextStyle} from './Tabs.style'; +import {TabsProps} from './Tab.type'; + +const Tabs: React.FC = ({children, tabsContainerStyle}) => { + const {theme} = useTheme(); + const [activeTabIndex, setActiveTabIndex] = useState(0); + + const isActive = (index: number) => activeTabIndex === index; + const tabItemCount = children.length; + + return ( + +
    + + {children.map((tabItem, index) => ( + + ))} +
    + +
+
+ {children[activeTabIndex].props.content} +
+
+ ); +}; + +export default Tabs; diff --git a/client/src/components/Design/components/Text/Text.stories.tsx b/HDesign/src/components/Text/Text.stories.tsx similarity index 93% rename from client/src/components/Design/components/Text/Text.stories.tsx rename to HDesign/src/components/Text/Text.stories.tsx index 9007b4756..5e5ec2287 100644 --- a/client/src/components/Design/components/Text/Text.stories.tsx +++ b/HDesign/src/components/Text/Text.stories.tsx @@ -1,6 +1,6 @@ import type {Meta, StoryObj} from '@storybook/react'; -import Text from '@HDcomponents/Text/Text'; +import Text from '@components/Text/Text'; const meta = { title: 'Components/Text', diff --git a/client/src/components/Design/components/Text/Text.style.ts b/HDesign/src/components/Text/Text.style.ts similarity index 90% rename from client/src/components/Design/components/Text/Text.style.ts rename to HDesign/src/components/Text/Text.style.ts index 858d136af..650260e62 100644 --- a/client/src/components/Design/components/Text/Text.style.ts +++ b/HDesign/src/components/Text/Text.style.ts @@ -23,8 +23,6 @@ export const getSizeStyling = ({size, textColor, theme}: Required = forwardRef diff --git a/client/src/components/Design/components/TextButton/TextButton.type.ts b/HDesign/src/components/TextButton/TextButton.type.ts similarity index 85% rename from client/src/components/Design/components/TextButton/TextButton.type.ts rename to HDesign/src/components/TextButton/TextButton.type.ts index 5a1287734..0299d89b9 100644 --- a/client/src/components/Design/components/TextButton/TextButton.type.ts +++ b/HDesign/src/components/TextButton/TextButton.type.ts @@ -1,6 +1,6 @@ import {TextSize} from '../Text/Text.type'; -export type TextColor = 'black' | 'gray' | 'onTertiary'; +export type TextColor = 'black' | 'gray'; export interface TextButtonStyleProps { textColor: TextColor; diff --git a/client/src/components/Design/components/Title/Title.stories.tsx b/HDesign/src/components/Title/Title.stories.tsx similarity index 59% rename from client/src/components/Design/components/Title/Title.stories.tsx rename to HDesign/src/components/Title/Title.stories.tsx index 899c78b83..2c91287b4 100644 --- a/client/src/components/Design/components/Title/Title.stories.tsx +++ b/HDesign/src/components/Title/Title.stories.tsx @@ -1,6 +1,6 @@ import type {Meta, StoryObj} from '@storybook/react'; -import Title from '@HDcomponents/Title/Title'; +import Title from '@components/Title/Title'; const meta = { title: 'Components/Title', @@ -14,14 +14,20 @@ const meta = { description: '', control: {type: 'text'}, }, - amount: { + description: { + description: '', + control: {type: 'text'}, + }, + price: { description: '', control: {type: 'number'}, }, }, args: { - title: 'ํ–‰๋™๋Œ€์žฅ ์•ผ์œ ํšŒ', - amount: 100000, + title: 'ํŽ˜์ด์ง€ ์ œ๋ชฉ์ด์—์š”', + description: `์ด๊ณณ์—๋Š” ํŽ˜์ด์ง€ ์„ค๋ช…์ด ๋“ค์–ด๊ฐ€์š”. + ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์ž์„ธํ•˜๊ฒŒ ์ ์–ด์ฃผ๋ฉด ์ข‹์•„์š” :)`, + price: 100000, }, } satisfies Meta; diff --git a/client/src/components/Design/components/Title/Title.style.ts b/HDesign/src/components/Title/Title.style.ts similarity index 51% rename from client/src/components/Design/components/Title/Title.style.ts rename to HDesign/src/components/Title/Title.style.ts index bd19002d1..ab347a214 100644 --- a/client/src/components/Design/components/Title/Title.style.ts +++ b/HDesign/src/components/Title/Title.style.ts @@ -2,26 +2,18 @@ import {css} from '@emotion/react'; import {Theme} from '@theme/theme.type'; -export const titleStyle = (theme: Theme) => +export const titleContainerStyle = (theme: Theme) => css({ display: 'flex', flexDirection: 'column', width: '100%', gap: '0.5rem', backgroundColor: theme.colors.white, - padding: '0.5rem', - borderRadius: '0.75rem', + padding: '1rem', }); -export const titleContainerStyle = css({ - display: 'flex', - justifyContent: 'space-between', - paddingLeft: '0.5rem', -}); - -export const amountContainerStyle = css({ +export const priceContainerStyle = css({ display: 'flex', justifyContent: 'space-between', alignItems: 'end', - paddingInline: '0.5rem', }); diff --git a/HDesign/src/components/Title/Title.tsx b/HDesign/src/components/Title/Title.tsx new file mode 100644 index 000000000..e17de5e88 --- /dev/null +++ b/HDesign/src/components/Title/Title.tsx @@ -0,0 +1,34 @@ +/** @jsxImportSource @emotion/react */ +import Flex from '@components/Flex/Flex'; +import Text from '@components/Text/Text'; +import {priceContainerStyle, titleContainerStyle} from '@components/Title/Title.style'; +import {TitleProps} from '@components/Title/Title.type'; + +import {useTheme} from '@theme/HDesignProvider'; + +export const Title: React.FC = ({title, description, price}: TitleProps) => { + const {theme} = useTheme(); + return ( +
+ {title} + {description && ( + + {description} + + )} + {price !== undefined && ( +
+ + ์ „์ฒด ์ง€์ถœ ๊ธˆ์•ก + + + {price.toLocaleString('ko-kr')} + ์› + +
+ )} +
+ ); +}; + +export default Title; diff --git a/client/src/components/Design/components/Title/Title.type.ts b/HDesign/src/components/Title/Title.type.ts similarity index 82% rename from client/src/components/Design/components/Title/Title.type.ts rename to HDesign/src/components/Title/Title.type.ts index cb28743f4..4b12f23b2 100644 --- a/client/src/components/Design/components/Title/Title.type.ts +++ b/HDesign/src/components/Title/Title.type.ts @@ -2,8 +2,8 @@ export interface TitleStyleProps {} export interface TitleCustomProps { title: string; - amount?: number; - dropdown?: React.ReactNode; + description?: string; + price?: number; } export type TitleOptionProps = TitleStyleProps & TitleCustomProps; diff --git a/HDesign/src/components/Toast/Toast.stories.tsx b/HDesign/src/components/Toast/Toast.stories.tsx new file mode 100644 index 000000000..fd672959c --- /dev/null +++ b/HDesign/src/components/Toast/Toast.stories.tsx @@ -0,0 +1,71 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import Toast from '@components/Toast/Toast'; + +const meta = { + title: 'Components/Toast', + component: Toast, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + args: { + type: 'confirm', + position: 'top', + top: '80px', + message: `์„œ๋ฒ„ ์˜ค๋ฅ˜๋กœ ์ธํ•ด ์ธ์›์„ ์„ค์ •ํ•˜๋Š”๋ฐ ์‹คํŒจํ–ˆ์–ด์š”. +๋‘๊ธ€์ž๋ฉด ์ด๋ ‡๊ฒŒ ๋ณด์—ฌ์š”.`, + onUndo: () => alert('๋˜๋Œ๋ฆฌ๊ธฐ ๋ฒ„ํŠผ์ด ๋ˆŒ๋ ธ์Šต๋‹ˆ๋‹ค. ์‹คํ–‰ํ•  ๋กœ์ง์„ ์ „๋‹ฌํ•ด์ฃผ์„ธ์š”'), + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const ConfirmToast: Story = { + args: { + ...meta.args, + type: 'confirm', + top: '80px', + message: `์ด ์ฒซ๋ฒˆ์งธ ํ† ์ŠคํŠธ ๊ทธ๋ฆผ์ž ์ง™์€๊ฑฐ ๋‘ ๊ฐœ ๋– ์„œ ๊ทธ๋Ÿฐ๊ฑฐ์ž„ css ์ž˜๋ชปํ•œ๊ฑฐ ์•„๋‹™๋‹ˆ๋‹ค. ์ž˜๋ชป ์—†์Šต๋‹ˆ๋‹ค. ์Šคํ† ๋ฆฌ๋ถ์ด ์ž˜๋ชปํ•œ๊ฑฐ์—์š”. ์ €ํฌ๋Š” ์ตœ์„ ์„ ๋‹คํ–ˆ์–ด์š”.. `, + }, +}; + +export const ConfirmToastWithoutUndo: Story = { + args: { + ...meta.args, + onUndo: undefined, + top: '160px', + }, +}; + +export const ErrorToast: Story = { + args: { + ...meta.args, + top: '240px', + type: 'error', + message: `๋‹˜ ์ด๊ฑฐ ๋‹ค ์ž‘์„ฑํ–ˆ๋Š”๋ฐ, ํ˜น์‹œ ๋˜๋Œ๋ฆผ? + ๋˜๋Œ๋ฆด ์ˆ˜๋„ ์žˆ์Œ ใ…‡ใ…‡ ๊ตฟ`, + }, +}; + +export const ErrorToastWithoutUndo: Story = { + args: { + ...meta.args, + top: '320px', + onUndo: undefined, + type: 'error', + }, +}; + +export const NoneToast: Story = { + args: { + ...meta.args, + top: '400px', + onUndo: undefined, + type: 'none', + message: '์›จ๋””๋Š” ์ปค๋น„์˜ ๋จน์ž‡๊ฐ์ธ๊ฐ€์š”? ๊ทธ์น˜๋งŒ ๊ฐ์ž๋Š” ์›จ๋””ํ•œํ…Œ ๋จนํž˜ ์ฟ ์Šค์ฟ ์Šค ใ…‹', + }, +}; diff --git a/HDesign/src/components/Toast/Toast.style.ts b/HDesign/src/components/Toast/Toast.style.ts new file mode 100644 index 000000000..0496bc722 --- /dev/null +++ b/HDesign/src/components/Toast/Toast.style.ts @@ -0,0 +1,44 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +import {ToastPosition} from './Toast.type'; + +type ToastMarginStyle = { + position?: ToastPosition; + bottom?: string; + top?: string; +}; + +export const toastMarginStyle = ({position, bottom, top}: ToastMarginStyle) => + css({ + position: 'absolute', + bottom: position === 'bottom' ? `${bottom}` : 'auto', + top: position === 'top' ? `${top}` : 'auto', + left: '50%', + transform: 'translate(-50%)', + + width: '100%', + maxWidth: '48rem', + paddingInline: '0.5rem', + }); + +export const toastStyle = (theme: Theme) => + css({ + width: '100%', + padding: '0.625rem 1rem', + + backgroundColor: theme.colors.gray, + boxShadow: '0 8px 12px rgba(0, 0, 0, 0.16);', + + borderRadius: '1.25rem', + }); + +export const textStyle = (theme: Theme) => + css({ + width: '100%', + + color: theme.colors.white, + + whiteSpace: 'pre-line', + }); diff --git a/HDesign/src/components/Toast/Toast.tsx b/HDesign/src/components/Toast/Toast.tsx new file mode 100644 index 000000000..972ce6220 --- /dev/null +++ b/HDesign/src/components/Toast/Toast.tsx @@ -0,0 +1,73 @@ +/** @jsxImportSource @emotion/react */ +import {createPortal} from 'react-dom'; + +import Text from '@components/Text/Text'; +import Flex from '@components/Flex/Flex'; +import Icon from '@components/Icon/Icon'; + +import {useTheme} from '@theme/HDesignProvider'; + +import Button from '../Button/Button'; + +import {toastStyle, textStyle, toastMarginStyle} from './Toast.style'; +import {ToastProps, ToastType} from './Toast.type'; + +const renderIcon = (type: ToastType) => { + switch (type) { + case 'error': + return ; + + case 'confirm': + return ; + + case 'none': + return null; + + default: + return null; + } +}; + +const Toast = ({ + type = 'confirm', + top = '0px', + bottom = '0px', + isClickToClose = true, + position = 'bottom', + message, + onUndo, + onClose, + ...htmlProps +}: ToastProps) => { + const {theme} = useTheme(); + const styleProps = {position, top, bottom}; + + const handleClickToClose = () => { + if (!isClickToClose || !onClose) return; + + onClose(); + }; + + return createPortal( +
+
+ + + {renderIcon(type)} + + {message} + + + {onUndo && ( + + )} + +
+
, + document.body, + ); +}; + +export default Toast; diff --git a/HDesign/src/components/Toast/Toast.type.ts b/HDesign/src/components/Toast/Toast.type.ts new file mode 100644 index 000000000..12a436c2d --- /dev/null +++ b/HDesign/src/components/Toast/Toast.type.ts @@ -0,0 +1,21 @@ +export type ToastPosition = 'bottom' | 'top'; +export type ToastType = 'error' | 'confirm' | 'none'; + +export interface ToastStyleProps { + bottom?: string; + top?: string; +} + +export interface ToastOptionProps { + position?: ToastPosition; + type?: ToastType; + onUndo?: () => void; + isClickToClose?: boolean; + onClose?: () => void; +} + +export interface ToastRequiredProps { + message: string; +} + +export type ToastProps = React.ComponentProps<'div'> & ToastStyleProps & ToastOptionProps & ToastRequiredProps; diff --git a/HDesign/src/components/Toast/ToastProvider.stories.tsx b/HDesign/src/components/Toast/ToastProvider.stories.tsx new file mode 100644 index 000000000..32c8c6917 --- /dev/null +++ b/HDesign/src/components/Toast/ToastProvider.stories.tsx @@ -0,0 +1,46 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import Button from '../Button/Button'; + +import {ToastProvider, useToast} from './ToastProvider'; + +const meta = { + title: 'Components/ToastProvider', + component: ToastProvider, + tags: ['autodocs'], + decorators: [ + Story => ( + + + + ), + ], +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = { + decorators: [ + () => { + const {showToast} = useToast(); + + return ( + + ); + }, + ], +}; diff --git a/HDesign/src/components/Toast/ToastProvider.tsx b/HDesign/src/components/Toast/ToastProvider.tsx new file mode 100644 index 000000000..9201fdc6d --- /dev/null +++ b/HDesign/src/components/Toast/ToastProvider.tsx @@ -0,0 +1,59 @@ +/** @jsxImportSource @emotion/react */ +import {createContext, useCallback, useContext, useEffect, useState} from 'react'; + +import {ToastProps} from './Toast.type'; +import Toast from './Toast'; + +export const ToastContext = createContext(null); + +interface ToastContextProps { + showToast: (args: ShowToast) => void; +} + +type ShowToast = ToastProps & { + showingTime?: number; + isAlwaysOn?: boolean; +}; + +const ToastProvider = ({children}: React.PropsWithChildren) => { + const [currentToast, setCurrentToast] = useState(null); + + const showToast = useCallback(({showingTime = 3000, isAlwaysOn = false, ...toastProps}: ShowToast) => { + setCurrentToast({showingTime, isAlwaysOn, ...toastProps}); + }, []); + + const closeToast = () => { + setCurrentToast(null); + }; + + useEffect(() => { + if (!currentToast) return; + + if (!currentToast.isAlwaysOn) { + const timer = setTimeout(() => { + setCurrentToast(null); + }, currentToast.showingTime); + + return () => clearTimeout(timer); + } + }, [currentToast]); + + return ( + + {currentToast && } + {children} + + ); +}; + +const useToast = () => { + const context = useContext(ToastContext); + + if (!context) { + throw new Error('useToast๋Š” ToastProvider ๋‚ด์—์„œ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.'); + } + + return context; +}; + +export {ToastProvider, useToast}; diff --git a/HDesign/src/components/TopNav/Back.tsx b/HDesign/src/components/TopNav/Back.tsx new file mode 100644 index 000000000..cfb55e24d --- /dev/null +++ b/HDesign/src/components/TopNav/Back.tsx @@ -0,0 +1,17 @@ +/** @jsxImportSource @emotion/react */ +import React from 'react'; +import {useNavigate} from 'react-router-dom'; + +import TextButton from '@components/TextButton/TextButton'; + +function Back() { + const navigate = useNavigate(); + + return ( + navigate(-1)} textSize="bodyBold" textColor="gray"> + ๋’ค๋กœ๊ฐ€๊ธฐ + + ); +} + +export default Back; diff --git a/HDesign/src/components/TopNav/TopNav.stories.tsx b/HDesign/src/components/TopNav/TopNav.stories.tsx new file mode 100644 index 000000000..0c96161a5 --- /dev/null +++ b/HDesign/src/components/TopNav/TopNav.stories.tsx @@ -0,0 +1,50 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import React from 'react'; +import {reactRouterParameters, withRouter} from 'storybook-addon-react-router-v6'; + +import TopNav from '@components/TopNav/TopNav'; + +import Switch from '../Switch/Switch'; + +import Back from './Back'; + +const meta = { + title: 'Components/TopNav', + component: TopNav, + tags: ['autodocs'], + decorators: [withRouter], + parameters: { + reactRouter: reactRouterParameters({ + location: { + pathParams: { + eventId: '123123', + }, + }, + routing: {path: '/event/:eventId/home'}, + }), + // layout: 'centered', + }, + argTypes: { + children: { + description: '', + control: {type: 'select'}, + options: ['Back', 'Switch', 'Any'], + mapping: { + Back: , + Switch: console.log(value)} />, + Any:
, + }, + }, + }, + args: { + children: 'Back', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/TopNav/TopNav.style.ts b/HDesign/src/components/TopNav/TopNav.style.ts new file mode 100644 index 000000000..9ca69c7b0 --- /dev/null +++ b/HDesign/src/components/TopNav/TopNav.style.ts @@ -0,0 +1,18 @@ +import {css} from '@emotion/react'; + +export const topNavStyle = css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '0 1rem', + width: '100%', +}); + +export const topNavNonStyle = css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '0 1rem', + width: '100%', + height: '1.5rem', +}); diff --git a/HDesign/src/components/TopNav/TopNav.tsx b/HDesign/src/components/TopNav/TopNav.tsx new file mode 100644 index 000000000..643cd5e3b --- /dev/null +++ b/HDesign/src/components/TopNav/TopNav.tsx @@ -0,0 +1,20 @@ +/** @jsxImportSource @emotion/react */ +import React from 'react'; + +import Switch from '@components/Switch/Switch'; + +import {topNavNonStyle, topNavStyle} from './TopNav.style'; +import Back from './Back'; + +const TopNav: React.FC = ({children}) => { + const hasBack = React.Children.toArray(children).some(child => React.isValidElement(child) && child.type === Back); + const hasSwitch = React.Children.toArray(children).some( + child => React.isValidElement(child) && child.type === Switch, + ); + + const isExistNav = hasBack || hasSwitch; + + return
{children}
; +}; + +export default TopNav; diff --git a/HDesign/src/index.tsx b/HDesign/src/index.tsx new file mode 100644 index 000000000..656690951 --- /dev/null +++ b/HDesign/src/index.tsx @@ -0,0 +1,62 @@ +import BottomSheet from '@components/BottomSheet/BottomSheet'; +import Button from '@components/Button/Button'; +import DragHandleItem from '@components/DragHandleItem/DragHandleItem'; +import DragHandleItemContainer from '@components/DragHandleItemContainer/DragHandleItemContainer'; +import EditableItem from '@components/EditableItem/EditableItem'; +import ExpenseList from '@components/ExpenseList/ExpenseList'; +import FixedButton from '@components/FixedButton/FixedButton'; +import Flex from '@components/Flex/Flex'; +import Icon from '@components/Icon/Icon'; +import IconButton from '@components/IconButton/IconButton'; +import Input from '@components/Input/Input'; +import LabelInput from '@components/LabelInput/LabelInput'; +import ListButton from '@components/ListButton/ListButton'; +import LabelGroupInput from '@components/LabelGroupInput/LabelGroupInput'; +import Search from '@components/Search/Search'; +import Switch from '@components/Switch/Switch'; +import Tab from '@components/Tabs/Tab'; +import Tabs from '@components/Tabs/Tabs'; +import Text from '@components/Text/Text'; +import TextButton from '@components/TextButton/TextButton'; +import Title from '@components/Title/Title'; +import Toast from '@components/Toast/Toast'; +import Back from '@components/TopNav/Back'; +import TopNav from '@components/TopNav/TopNav'; +import {ToastProvider, useToast} from '@components/Toast/ToastProvider'; + +import {MainLayout} from '@layouts/MainLayout'; +import {ContentLayout} from '@layouts/ContentLayout'; + +import {HDesignProvider} from '@theme/HDesignProvider'; + +export { + BottomSheet, + Button, + DragHandleItem, + DragHandleItemContainer, + EditableItem, + ExpenseList, + FixedButton, + Flex, + Icon, + IconButton, + Input, + LabelInput, + ListButton, + LabelGroupInput, + Search, + Switch, + Tab, + Tabs, + Text, + TextButton, + Title, + Toast, + TopNav, + Back, + MainLayout, + ContentLayout, + ToastProvider, + useToast, + HDesignProvider, +}; diff --git a/client/src/components/Design/layouts/ContentLayout.tsx b/HDesign/src/layouts/ContentLayout.tsx similarity index 100% rename from client/src/components/Design/layouts/ContentLayout.tsx rename to HDesign/src/layouts/ContentLayout.tsx diff --git a/client/src/components/Design/layouts/MainLayout.tsx b/HDesign/src/layouts/MainLayout.tsx similarity index 96% rename from client/src/components/Design/layouts/MainLayout.tsx rename to HDesign/src/layouts/MainLayout.tsx index d7a699662..22012fde8 100644 --- a/client/src/components/Design/layouts/MainLayout.tsx +++ b/HDesign/src/layouts/MainLayout.tsx @@ -15,7 +15,7 @@ export function MainLayout({backgroundColor, children}: MainLayoutProps) { justifyContent="flexStart" flexDirection="column" padding="1rem 0 0 0" - gap="0.5rem" + gap="1rem" width="100%" height="100%" minHeight="100vh" diff --git a/client/src/components/Design/theme/GlobalStyle.ts b/HDesign/src/theme/GlobalStyle.ts similarity index 81% rename from client/src/components/Design/theme/GlobalStyle.ts rename to HDesign/src/theme/GlobalStyle.ts index b25bb94d1..f1b7b699b 100644 --- a/client/src/components/Design/theme/GlobalStyle.ts +++ b/HDesign/src/theme/GlobalStyle.ts @@ -1,9 +1,6 @@ import {css} from '@emotion/react'; -// reset css -> index css export const GlobalStyle = css` - @import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css'); - *:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) { all: unset; display: revert; @@ -123,26 +120,4 @@ export const GlobalStyle = css` button { cursor: pointer; } - - body { - font-family: - 'Pretendard', - -apple-system, - BlinkMacSystemFont, - system-ui, - Roboto, - 'Helvetica Neue', - 'Segoe UI', - 'Apple SD Gothic Neo', - 'Noto Sans KR', - 'Malgun Gothic', - 'Apple Color Emoji', - 'Segoe UI Emoji', - 'Segoe UI Symbol', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - max-width: 768px; - margin: 0 auto; - } `; diff --git a/client/src/components/Design/theme/HDesignProvider.tsx b/HDesign/src/theme/HDesignProvider.tsx similarity index 94% rename from client/src/components/Design/theme/HDesignProvider.tsx rename to HDesign/src/theme/HDesignProvider.tsx index c5367afa1..6c7c571a3 100644 --- a/client/src/components/Design/theme/HDesignProvider.tsx +++ b/HDesign/src/theme/HDesignProvider.tsx @@ -3,9 +3,9 @@ import {Global} from '@emotion/react'; import {Theme} from '@theme/theme.type'; import {GlobalStyle} from '@theme/GlobalStyle'; + import {COLORS} from '@token/colors'; import {TYPOGRAPHY} from '@token/typography'; -import {ZINDEX} from '@token/zIndex'; interface ThemeContextProps { theme: Theme; @@ -14,7 +14,6 @@ interface ThemeContextProps { const defaultTheme: Theme = { colors: COLORS, typography: TYPOGRAPHY, - zIndex: ZINDEX, }; const ThemeContext = createContext(undefined); diff --git a/client/src/components/Design/theme/theme.type.ts b/HDesign/src/theme/theme.type.ts similarity index 72% rename from client/src/components/Design/theme/theme.type.ts rename to HDesign/src/theme/theme.type.ts index c6dbe0544..dffd961f0 100644 --- a/client/src/components/Design/theme/theme.type.ts +++ b/HDesign/src/theme/theme.type.ts @@ -1,9 +1,7 @@ import {ColorTokens} from '@token/colors'; import {TypographyTokens} from '@token/typography'; -import {ZIndexTokens} from '@token/zIndex'; export interface Theme { colors: ColorTokens; typography: TypographyTokens; - zIndex: ZIndexTokens; } diff --git a/client/src/components/Design/token/colors.ts b/HDesign/src/token/colors.ts similarity index 100% rename from client/src/components/Design/token/colors.ts rename to HDesign/src/token/colors.ts diff --git a/client/src/components/Design/token/typography.ts b/HDesign/src/token/typography.ts similarity index 100% rename from client/src/components/Design/token/typography.ts rename to HDesign/src/token/typography.ts diff --git a/client/src/components/Design/type/strictPropsWithChildren.ts b/HDesign/src/type/strictPropsWithChildren.ts similarity index 100% rename from client/src/components/Design/type/strictPropsWithChildren.ts rename to HDesign/src/type/strictPropsWithChildren.ts diff --git a/client/src/components/Design/type/withTheme.ts b/HDesign/src/type/withTheme.ts similarity index 100% rename from client/src/components/Design/type/withTheme.ts rename to HDesign/src/type/withTheme.ts diff --git a/client/src/components/Design/utils/changeCamelCaseToKebabCase.ts b/HDesign/src/utils/changeCamelCaseToKebabCase.ts similarity index 100% rename from client/src/components/Design/utils/changeCamelCaseToKebabCase.ts rename to HDesign/src/utils/changeCamelCaseToKebabCase.ts diff --git a/client/src/components/Design/utils/colors.ts b/HDesign/src/utils/colors.ts similarity index 100% rename from client/src/components/Design/utils/colors.ts rename to HDesign/src/utils/colors.ts diff --git a/HDesign/tsconfig.json b/HDesign/tsconfig.json new file mode 100644 index 000000000..ca7b8b78f --- /dev/null +++ b/HDesign/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "sourceMap": true, + "outDir": "./dist", + "target": "ES5", + "skipLibCheck": true, + "module": "commonjs", + "moduleResolution": "node", + "strict": true, + "declaration": true, + "declarationDir": "./dist", + "resolveJsonModule": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "jsx": "react-jsx", + "allowJs": true, + "baseUrl": ".", + "paths": { + "@*": ["src/*"], + "@components/*": ["src/components/*"], + "@layouts/*": ["src/layouts/*"], + "@token/*": ["src/token/*"], + "@type/*": ["src/type/*"], + "@theme/*": ["src/theme/*"], + "@assets/*": ["src/assets/*"], + "@utils/*": ["src/utils/*"] + }, + "jsxImportSource": "@emotion/react", + "allowSyntheticDefaultImports": true + }, + "include": ["src"], + "exclude": ["./node_modules", "dist"] +} diff --git a/README.md b/README.md index c0b59222a..4bf6bd7c1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1 @@ -# ํ–‰๋™๋Œ€์žฅ๋“ค์˜ ์ •์‚ฐ์„ ๊ฐ„ํŽธํ•˜๊ฒŒ๐Ÿ’ฐํ–‰๋™๋Œ€์žฅ - -![service introduce](https://github.com/user-attachments/assets/9e51f7a3-0326-4c06-8b03-65aca574c10c) +# 2024-haeng-dong \ No newline at end of file diff --git a/client/.gitignore b/client/.gitignore index 54b01c541..cf03bec6b 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -12,6 +12,3 @@ dist # Sentry Config File .env.sentry-build-plugin - -storybook-static -*storybook.log diff --git a/client/.storybook/main.ts b/client/.storybook/main.ts deleted file mode 100644 index a06f80f22..000000000 --- a/client/.storybook/main.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** @type { import('@storybook/react-webpack5').StorybookConfig } */ -import type {StorybookConfig} from '@storybook/react-webpack5'; -import path from 'path'; -import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'; - -const config: StorybookConfig = { - stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], - addons: [ - '@storybook/addon-webpack5-compiler-swc', - '@storybook/addon-onboarding', - '@storybook/addon-links', - '@storybook/addon-essentials', - '@chromatic-com/storybook', - '@storybook/addon-interactions', - ], - framework: { - name: '@storybook/react-webpack5', - options: {}, - }, - webpackFinal: async config => { - if (config.resolve) { - config.resolve.alias = { - ...config.resolve.alias, - '@apis': path.resolve(__dirname, '../src/apis/'), - '@assets': path.resolve(__dirname, '../src/assets/'), - '@components': path.resolve(__dirname, '../src/components/'), - '@constants': path.resolve(__dirname, '../src/constants/'), - '@hooks': path.resolve(__dirname, '../src/hooks/'), - '@store': path.resolve(__dirname, '../src/store/'), - '@mocks': path.resolve(__dirname, '../src/mocks/'), - '@pages': path.resolve(__dirname, '../src/pages/'), - '@utils': path.resolve(__dirname, '../src/utils/'), - '@errors': path.resolve(__dirname, '../src/errors/'), - '@HDesign': path.resolve(__dirname, '../src/components/Design/'), - '@HDcomponents': path.resolve(__dirname, '../src/components/Design/components/'), - '@HDutils': path.resolve(__dirname, '../src/components/Design/utils/'), - '@token': path.resolve(__dirname, '../src/components/Design/token/'), - '@theme': path.resolve(__dirname, '../src/components/Design/theme/'), - '@layouts': path.resolve(__dirname, '../src/components/Design/layouts/'), - '@type': path.resolve(__dirname, '../src/components/Design/type/'), - }; - } - - config.module = config.module || {}; - config.module.rules = config.module.rules || []; - - const imageRule = config.module.rules.find(rule => rule?.['test']?.test('.svg')); - if (imageRule) { - imageRule['exclude'] = /\.svg$/; - } - - config.module.rules.push({ - test: /\.svg$/, - use: ['@svgr/webpack'], - }); - return config; - }, -}; -export default config; diff --git a/client/cypress/e2e/createEvent.cy.ts b/client/cypress/e2e/createEvent.cy.ts index 30e50b4f5..5b4a93884 100644 --- a/client/cypress/e2e/createEvent.cy.ts +++ b/client/cypress/e2e/createEvent.cy.ts @@ -1,27 +1,24 @@ -import {ROUTER_URLS} from '@constants/routerUrls'; import CONSTANTS from '../constants/constants'; -import RULE from '@constants/rule'; - beforeEach(() => { cy.blockSentry(); - cy.blockKakao(); }); describe('Flow: ๋žœ๋”ฉ ํŽ˜์ด์ง€์—์„œ๋ถ€ํ„ฐ ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑ ์™„๋ฃŒํ•˜๋Š” flow', () => { - it('๋žœ๋”ฉํŽ˜์ด์ง€์—์„œ "์ •์‚ฐ ์‹œ์ž‘ํ•˜๊ธฐ" ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ํ–‰์‚ฌ ์ด๋ฆ„ ์ž…๋ ฅ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ด์•ผ ํ•œ๋‹ค.', () => { + it('๋žœ๋”ฉํŽ˜์ด์ง€์—์„œ "ํ–‰์‚ฌ ์ƒ์„ฑํ•˜๊ธฐ" ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ํ–‰์‚ฌ ์ด๋ฆ„ ์ž…๋ ฅ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ด์•ผ ํ•œ๋‹ค.', () => { cy.visit('/'); - cy.get('button').contains('์ •์‚ฐ ์‹œ์ž‘ํ•˜๊ธฐ').click(); - cy.url().should('include', ROUTER_URLS.createEvent); + cy.get('header').find('button').click(); + cy.url().should('include', '/event/create/name'); }); context('ํ–‰์‚ฌ ์ด๋ฆ„ ์ž…๋ ฅ ํŽ˜์ด์ง€', () => { beforeEach(() => { - cy.visit(ROUTER_URLS.createEvent); + cy.visit('/event/create/name'); }); it('ํ–‰์‚ฌ ์ด๋ฆ„ ์ž…๋ ฅ ํŽ˜์ด์ง€์—์„œ input์ด ํฌ์ปค์‹ฑ ๋˜์–ด ์žˆ๊ณ , "๋‹ค์Œ" ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™” ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.', () => { cy.get('input').focused(); cy.get('button').contains('๋‹ค์Œ').should('have.attr', 'disabled'); + cy.url().should('include', '/event/create/name'); }); it('ํ–‰์‚ฌ ์ด๋ฆ„์ด 1์ž ์ด์ƒ ์ž…๋ ฅ๋œ ๊ฒฝ์šฐ "๋‹ค์Œ" ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™” ๋˜๊ณ , ๊ฐ’์ด ์—†๋Š” ๊ฒฝ์šฐ "๋‹ค์Œ" ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™” ๋˜์–ด์•ผ ํ•œ๋‹ค.', () => { @@ -30,14 +27,13 @@ describe('Flow: ๋žœ๋”ฉ ํŽ˜์ด์ง€์—์„œ๋ถ€ํ„ฐ ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑ ์™„๋ฃŒํ•˜๋Š” fl cy.get('input').clear(); cy.get('input').should('have.value', ''); cy.get('button').contains('๋‹ค์Œ').should('have.attr', 'disabled'); + cy.url().should('include', '/event/create/name'); }); it('ํ–‰์‚ฌ ์ด๋ฆ„์„ ์ž…๋ ฅํ•œ ํ›„ "๋‹ค์Œ" ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ–‰์‚ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ ์„ค์ • ํ™”๋ฉด์œผ๋กœ ์ด๋™ํ•ด์•ผ ํ•œ๋‹ค.', () => { cy.get('input').type(CONSTANTS.eventName); cy.get('button').contains('๋‹ค์Œ').click(); - - // ๋‹ค์Œ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด /create/event ๊ฒฝ๋กœ๊ฐ€ ์•„๋‹ˆ๋ผ /create/event/?๋กœ ๊ฐ€๋„ค์š”.. ๊ทธ๋ž˜์„œ ์ผ๋‹จ ์ œ๊ฑฐํ•จ. - cy.contains('๋น„๋ฐ€๋ฒˆํ˜ธ').should('exist'); + cy.url().should('include', '/event/create/password'); }); }); @@ -49,6 +45,7 @@ describe('Flow: ๋žœ๋”ฉ ํŽ˜์ด์ง€์—์„œ๋ถ€ํ„ฐ ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑ ์™„๋ฃŒํ•˜๋Š” fl it('ํ–‰์‚ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํŽ˜์ด์ง€์—์„œ input์ด ํฌ์ปค์‹ฑ ๋˜์–ด ์žˆ๊ณ , "ํ–‰๋™ ๊ฐœ์‹œ!" ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™” ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.', () => { cy.get('input').focused(); cy.get('button').contains('ํ–‰๋™ ๊ฐœ์‹œ!').should('have.attr', 'disabled'); + cy.url().should('include', '/event/create/password'); }); it('ํ–‰์‚ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ์— ์ˆซ์ž๊ฐ€ ์•„๋‹Œ ์ž…๋ ฅ์„ ํ•  ๊ฒฝ์šฐ ๊ฐ’์ด ์ž…๋ ฅ๋˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค.', () => { @@ -56,7 +53,7 @@ describe('Flow: ๋žœ๋”ฉ ํŽ˜์ด์ง€์—์„œ๋ถ€ํ„ฐ ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑ ์™„๋ฃŒํ•˜๋Š” fl cy.get('input').should('have.value', ''); }); - it(`ํ–‰์‚ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ์— ${RULE.maxEventPasswordLength}์ž๋ฆฌ ์ด์ƒ ์ž…๋ ฅ์„ ํ•  ๊ฒฝ์šฐ ์ฒ˜์Œ ${RULE.maxEventPasswordLength}์ž๋ฆฌ๋งŒ ์ž…๋ ฅ๋˜์–ด์•ผ ํ•œ๋‹ค.`, () => { + it('ํ–‰์‚ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ์— 4์ž๋ฆฌ ์ด์ƒ ์ž…๋ ฅ์„ ํ•  ๊ฒฝ์šฐ ์ฒ˜์Œ ๋„ค ์ž๋ฆฌ๋งŒ ์ž…๋ ฅ๋˜์–ด์•ผ ํ•œ๋‹ค.', () => { cy.get('input').type('12345'); cy.get('input').should('have.value', CONSTANTS.eventPassword); }); @@ -67,6 +64,7 @@ describe('Flow: ๋žœ๋”ฉ ํŽ˜์ด์ง€์—์„œ๋ถ€ํ„ฐ ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑ ์™„๋ฃŒํ•˜๋Š” fl cy.get('input').clear(); cy.get('input').should('have.value', ''); cy.get('button').contains('ํ–‰๋™ ๊ฐœ์‹œ!').should('have.attr', 'disabled'); + cy.url().should('include', '/event/create/password'); }); it('ํ–‰์‚ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ์„ ์ž…๋ ฅํ•œ ํ›„ "ํ–‰๋™ ๊ฐœ์‹œ!" ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ–‰์‚ฌ ์ƒ์„ฑ ์™„๋ฃŒ ํ™”๋ฉด์œผ๋กœ ์ด๋™ํ•ด์•ผ ํ•œ๋‹ค.', () => { @@ -74,6 +72,8 @@ describe('Flow: ๋žœ๋”ฉ ํŽ˜์ด์ง€์—์„œ๋ถ€ํ„ฐ ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑ ์™„๋ฃŒํ•˜๋Š” fl cy.interceptAPI({type: 'getEventName', statusCode: 200}); cy.get('input').type(CONSTANTS.eventPassword); cy.get('button').contains('ํ–‰๋™ ๊ฐœ์‹œ!').click(); + + cy.url().should('include', '/event/create/complete'); }); }); }); diff --git a/client/cypress/support/commands.ts b/client/cypress/support/commands.ts index 6ef75b4dc..c51d00580 100644 --- a/client/cypress/support/commands.ts +++ b/client/cypress/support/commands.ts @@ -1,4 +1,3 @@ -import {ROUTER_URLS} from '@constants/routerUrls'; import CONSTANTS from '../constants/constants'; type APIType = 'sentry' | 'postEvent' | 'getEventName'; @@ -22,13 +21,6 @@ Cypress.Commands.add('blockSentry', () => { cy.intercept('POST', /.*sentry.io\/api.*/, {statusCode: 200}).as('sentry'); }); -Cypress.Commands.add('blockKakao', () => { - cy.intercept('GET', 'https://t1.kakaocdn.net/kakao_js_sdk/2.7.2/kakao.min.js', { - statusCode: 200, - body: '', - }).as('blockKakao'); -}); - Cypress.Commands.add('interceptAPI', ({type, delay = 0, statusCode = 200}: InterceptAPIProps) => { if (type === 'postEvent') cy.intercept(POST_EVENT, { @@ -47,16 +39,16 @@ Cypress.Commands.add('interceptAPI', ({type, delay = 0, statusCode = 200}: Inter }); Cypress.Commands.add('createEventName', (eventName: string) => { - cy.visit(ROUTER_URLS.createEvent); + cy.visit('/event/create/name'); cy.get('input').type(eventName); cy.get('button').contains('๋‹ค์Œ').click(); + cy.url().should('include', '/event/create/password'); }); declare global { namespace Cypress { interface Chainable { blockSentry(): Chainable; - blockKakao(): Chainable; interceptAPI(props: InterceptAPIProps): Chainable; createEventName(eventName: string): Chainable; } diff --git a/client/eslint.config.mjs b/client/eslint.config.mjs index e8355aaed..4ca5abb89 100644 --- a/client/eslint.config.mjs +++ b/client/eslint.config.mjs @@ -71,11 +71,6 @@ export default [ group: 'internal', position: 'after', }, - { - pattern: '@HDesign/*', - group: 'internal', - position: 'after', - }, { pattern: '@utils/*', group: 'internal', diff --git a/client/index.html b/client/index.html index 5252bb218..4a21293f2 100644 --- a/client/index.html +++ b/client/index.html @@ -25,11 +25,6 @@ window.amplitude.init('<%= process.env.AMPLITUDE_KEY %>'); }); - ํ–‰๋™๋Œ€์žฅ diff --git a/client/jest.config.ts b/client/jest.config.ts index 5cdc6baab..a75677a5a 100644 --- a/client/jest.config.ts +++ b/client/jest.config.ts @@ -6,7 +6,6 @@ const config: Config = { testEnvironment: 'jsdom', // ๋ธŒ๋ผ์šฐ์ € ๋‚ด์—์„œ์˜ JavaScript ๋™์ž‘์„ ๋ชจ๋ฐฉํ•˜์—ฌ, DOM ์กฐ์ž‘, ์ด๋ฒคํŠธ ํ•ธ๋“ค๋ง, ๋ธŒ๋ผ์šฐ์ € ๊ด€๋ จ API ํ˜ธ์ถœ transform: { '^.+\\.ts?$': 'ts-jest', - '^.+\\.(jpg|jpeg|png|gif|svg)$': '/src/mocks/imageFileMock.ts', }, collectCoverage: true, coverageReporters: ['text'], @@ -31,7 +30,6 @@ const config: Config = { moduleNameMapper: { '@/(.*)$': '/src/$1', // path alias๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•จ '^@apis/(.*)$': '/src/apis/$1', - '^@assets/(.*)$': '/src/assets/$1', '^@constants/(.*)$': '/src/constants/$1', '^@components/(.*)$': '/src/components/$1', '^@hooks/(.*)$': '/src/hooks/$1', @@ -41,14 +39,7 @@ const config: Config = { '^@errors/(.*)$': '/src/errors/$1', '^@mocks/(.*)$': '/src/mocks/$1', '^@store/(.*)$': '/src/store/$1', - '^@HDesign/(.*)$': '/src/components/Design/$1', - '^@HDcomponents/(.*)$': '/src/components/Design/components/$1', - '^@HDutils/(.*)$': '/src/components/Design/utils/$1', - '^@token/(.*)$': '/src/components/Design/token/$1', - '^@theme/(.*)$': '/src/components/Design/theme/$1', - '^@layouts/(.*)$': '/src/components/Design/layouts/$1', - '^@type/(.*)$': '/src/components/Design/type/$1', - '\\.(jpg|jpeg|png|gif|svg)$': '/src/mocks/imageFileMock.ts', + '\\.svg$': '/src/mocks/svg.ts', }, testEnvironmentOptions: { customExportConditions: [''], diff --git a/client/package-lock.json b/client/package-lock.json index 95211e1e6..61a529538 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -12,7 +12,8 @@ "@emotion/react": "^11.11.4", "@sentry/react": "^8.25.0", "@tanstack/react-query": "^5.51.23", - "lottie-react": "^2.4.0", + "haengdong-design": "^0.1.81", + "jest-canvas-mock": "^2.5.2", "react": "^18.3.1", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", @@ -21,20 +22,10 @@ "zustand": "^4.5.5" }, "devDependencies": { - "@chromatic-com/storybook": "^1.6.1", "@eslint/compat": "^1.1.0", "@eslint/js": "^9.6.0", "@jest/types": "^29.6.3", "@sentry/webpack-plugin": "^2.22.0", - "@storybook/addon-essentials": "^8.2.2", - "@storybook/addon-interactions": "^8.2.2", - "@storybook/addon-links": "^8.2.2", - "@storybook/addon-onboarding": "^8.2.2", - "@storybook/addon-webpack5-compiler-swc": "^1.0.5", - "@storybook/blocks": "^8.2.2", - "@storybook/react": "^8.2.2", - "@storybook/react-webpack5": "^8.2.3", - "@storybook/test": "^8.2.2", "@svgr/webpack": "^8.1.0", "@tanstack/react-query-devtools": "^5.52.0", "@testing-library/dom": "^10.4.0", @@ -57,21 +48,16 @@ "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-react": "^7.34.3", "eslint-plugin-react-hooks": "^4.6.2", - "file-loader": "^6.2.0", "fork-ts-checker-webpack-plugin": "^9.0.2", "globals": "^15.8.0", "html-loader": "^5.0.0", "html-webpack-plugin": "^5.6.0", "jest": "^29.7.0", - "jest-canvas-mock": "^2.5.2", "jest-environment-jsdom": "^29.7.0", - "jest-transform-stub": "^2.0.0", "jsdom": "^24.1.1", "modify-source-webpack-plugin": "^4.1.0", "msw": "^2.3.5", "prettier": "3.3.2", - "storybook": "^8.2.2", - "storybook-addon-react-router-v6": "^2.0.15", "ts-jest": "^29.2.4", "ts-loader": "^9.5.1", "ts-node": "^10.9.2", @@ -98,7 +84,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -123,7 +108,6 @@ "version": "7.25.2", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -132,7 +116,6 @@ "version": "7.25.2", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", - "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", @@ -161,8 +144,7 @@ "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/@babel/generator": { "version": "7.25.0", @@ -182,7 +164,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -194,7 +175,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -207,7 +187,6 @@ "version": "7.25.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.25.2", "@babel/helper-validator-option": "^7.24.8", @@ -223,7 +202,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz", "integrity": "sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-member-expression-to-functions": "^7.24.8", @@ -244,7 +222,6 @@ "version": "7.25.2", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "regexpu-core": "^5.3.1", @@ -261,7 +238,6 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", - "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -277,7 +253,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.8", "@babel/types": "^7.24.8" @@ -302,7 +277,6 @@ "version": "7.25.2", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", - "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.24.7", "@babel/helper-simple-access": "^7.24.7", @@ -320,7 +294,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -332,7 +305,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -341,7 +313,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-wrap-function": "^7.25.0", @@ -358,7 +329,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", - "dev": true, "dependencies": { "@babel/helper-member-expression-to-functions": "^7.24.8", "@babel/helper-optimise-call-expression": "^7.24.7", @@ -375,7 +345,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -388,7 +357,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -417,7 +385,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -426,7 +393,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", - "dev": true, "dependencies": { "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.0", @@ -440,7 +406,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", - "dev": true, "dependencies": { "@babel/template": "^7.25.0", "@babel/types": "^7.25.0" @@ -481,7 +446,6 @@ "version": "7.25.3", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", "@babel/traverse": "^7.25.3" @@ -497,7 +461,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -512,7 +475,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -527,7 +489,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", @@ -544,7 +505,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", "@babel/traverse": "^7.25.0" @@ -560,7 +520,6 @@ "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, "engines": { "node": ">=6.9.0" }, @@ -572,7 +531,6 @@ "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -596,7 +554,6 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -608,7 +565,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -623,7 +579,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -635,7 +590,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.3" }, @@ -643,26 +597,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.7.tgz", - "integrity": "sha512-9G8GYT/dxn/D1IIKOUBmGX0mnmj46mGH9NnZyJLwtCpgh5f7D2VbuKodb+2s9m1Yavh1s7ASQN8lf0eqrb1LTw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -677,7 +615,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -692,7 +629,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -704,7 +640,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -716,7 +651,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -731,7 +665,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -743,7 +676,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -755,7 +687,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -767,7 +698,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -779,7 +709,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -791,7 +720,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -803,7 +731,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -818,7 +745,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -833,7 +759,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -848,7 +773,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -864,7 +788,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -879,7 +802,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz", "integrity": "sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-remap-async-to-generator": "^7.25.0", @@ -897,7 +819,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", - "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -914,7 +835,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -929,7 +849,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -944,7 +863,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", - "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -960,7 +878,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", - "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -977,7 +894,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.0.tgz", "integrity": "sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-compilation-targets": "^7.24.8", @@ -997,7 +913,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } @@ -1006,7 +921,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/template": "^7.24.7" @@ -1022,7 +936,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -1037,7 +950,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1053,7 +965,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1068,7 +979,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.0", "@babel/helper-plugin-utils": "^7.24.8" @@ -1084,7 +994,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" @@ -1100,7 +1009,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", - "dev": true, "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1116,7 +1024,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" @@ -1128,27 +1035,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.25.2.tgz", - "integrity": "sha512-InBZ0O8tew5V0K6cHcQ+wgxlrjOw1W4wDXLkOTjLRD8GYhTSkxTVBtdy3MMtvYBrbAWa1Qm3hNoTc1620Yj+Mg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/plugin-syntax-flow": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-for-of": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" @@ -1164,7 +1054,6 @@ "version": "7.25.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", - "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.24.8", "@babel/helper-plugin-utils": "^7.24.8", @@ -1181,7 +1070,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-json-strings": "^7.8.3" @@ -1197,7 +1085,6 @@ "version": "7.25.2", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -1212,7 +1099,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" @@ -1228,7 +1114,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1243,7 +1128,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", - "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1259,7 +1143,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", - "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.24.8", "@babel/helper-plugin-utils": "^7.24.8", @@ -1276,7 +1159,6 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", - "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.25.0", "@babel/helper-plugin-utils": "^7.24.8", @@ -1294,7 +1176,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", - "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1310,7 +1191,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1326,7 +1206,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1341,7 +1220,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -1357,7 +1235,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -1373,7 +1250,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", - "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -1391,7 +1267,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-replace-supers": "^7.24.7" @@ -1407,7 +1282,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" @@ -1423,7 +1297,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", @@ -1440,7 +1313,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1455,7 +1327,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", - "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1471,7 +1342,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-create-class-features-plugin": "^7.24.7", @@ -1489,7 +1359,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1504,7 +1373,6 @@ "version": "7.25.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.1.tgz", "integrity": "sha512-SLV/giH/V4SmloZ6Dt40HjTGTAIkxn33TVIHxNGNvo8ezMhrxBkzisj4op1KZYPIOHFLqhv60OHvX+YRu4xbmQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -1519,7 +1387,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1534,7 +1401,6 @@ "version": "7.25.2", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.2.tgz", "integrity": "sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", @@ -1553,7 +1419,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", - "dev": true, "dependencies": { "@babel/plugin-transform-react-jsx": "^7.24.7" }, @@ -1568,7 +1433,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1584,7 +1448,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "regenerator-transform": "^0.15.2" @@ -1600,7 +1463,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1615,7 +1477,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1630,7 +1491,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" @@ -1646,7 +1506,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1661,7 +1520,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1676,7 +1534,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -1691,7 +1548,6 @@ "version": "7.25.2", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.2.tgz", "integrity": "sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-create-class-features-plugin": "^7.25.0", @@ -1710,7 +1566,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1725,7 +1580,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1741,7 +1595,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1757,7 +1610,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1773,7 +1625,6 @@ "version": "7.25.3", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.3.tgz", "integrity": "sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.25.2", "@babel/helper-compilation-targets": "^7.25.2", @@ -1866,28 +1717,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-flow": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.7.tgz", - "integrity": "sha512-NL3Lo0NorCU607zU3NwRyJbpaB6E3t0xtd3LfAQKDfkeX4/ggcDXvkmkW42QWT5owUeW/jAe4hn+2qvkV1IbfQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-transform-flow-strip-types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", @@ -1901,7 +1734,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-validator-option": "^7.24.7", @@ -1921,7 +1753,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-validator-option": "^7.24.7", @@ -1936,148 +1767,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/register": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.24.6.tgz", - "integrity": "sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "find-cache-dir": "^2.0.0", - "make-dir": "^2.1.0", - "pirates": "^4.0.6", - "source-map-support": "^0.5.16" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/register/node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@babel/register/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/register/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/@babel/regjsgen": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { "version": "7.25.0", @@ -2141,12 +1834,6 @@ "node": ">=6.9.0" } }, - "node_modules/@base2/pretty-print-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", - "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", - "dev": true - }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -2190,58 +1877,14 @@ "tough-cookie": "^4.1.4" } }, - "node_modules/@chromatic-com/storybook": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-1.8.0.tgz", - "integrity": "sha512-vkB9dPVmM2Yvqc/0DJ4MYwOGY1MOjd/KbB9TXTMGN+qshaEyiZtSOgbz9u0ExFALEgDKLmtUnWyUtoGb0pCzUg==", + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, - "dependencies": { - "chromatic": "^11.4.0", - "filesize": "^10.0.12", - "jsonfile": "^6.1.0", - "react-confetti": "^6.1.0", - "strip-ansi": "^7.1.0" - }, + "optional": true, "engines": { - "node": ">=16.0.0", - "yarn": ">=1.22.18" - } - }, - "node_modules/@chromatic-com/storybook/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@chromatic-com/storybook/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.1.90" + "node": ">=0.1.90" } }, "node_modules/@cspotcode/source-map-support": { @@ -2441,591 +2084,501 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, - "optional": true, - "os": [ - "aix" - ], + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=12" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/compat": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.1.tgz", + "integrity": "sha512-lpHyRyplhGPL5mGEh6M9O5nnKk0Gz4bFI+Zu6tKlPpDUN7XshWvH9C/px4UVm87IAANE0W81CEsNGbS1KlzXpA==", "dev": true, - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", "dev": true, - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=12" + "node": "*" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=12" + "node": "*" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], + "node_modules/@eslint/js": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", + "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": ">=14" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], + "node_modules/@inquirer/confirm": { + "version": "3.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.22.tgz", + "integrity": "sha512-gsAKIOWBm2Q87CDfs9fEo7wJT3fwWIJfnDGMn9Qy74gBnNFOACDNfhUzovubbJjWnKLGBln7/NcSmZwj5DuEXg==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2" + }, "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/core": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", + "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@inquirer/figures": "^1.0.5", + "@inquirer/type": "^1.5.2", + "@types/mute-stream": "^0.0.4", + "@types/node": "^22.1.0", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "mute-stream": "^1.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "optional": true, - "os": [ - "netbsd" - ], + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=12" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "optional": true, - "os": [ - "openbsd" - ], + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=12" + "node": ">=7.0.0" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@inquirer/core/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "optional": true, - "os": [ - "sunos" - ], "engines": { - "node": ">=12" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/core/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/figures": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.5.tgz", + "integrity": "sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA==", "dev": true, - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "node_modules/@inquirer/type": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.2.tgz", + "integrity": "sha512-w9qFkumYDCNyDZmNQjf/n6qQuvQ4dMC3BJesY4oF+yr0CxR5vxujflAVeIcS6U336uzi9GM0kAfZlLrZ9UTkpA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "mute-stream": "^1.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=18" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=12" } }, - "node_modules/@eslint/compat": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.1.tgz", - "integrity": "sha512-lpHyRyplhGPL5mGEh6M9O5nnKk0Gz4bFI+Zu6tKlPpDUN7XshWvH9C/px4UVm87IAANE0W81CEsNGbS1KlzXpA==", + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@eslint/config-array": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", - "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" + "ansi-regex": "^6.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "sprintf-js": "~1.0.2" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=6" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=8" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", - "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=8" } }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, "engines": { - "node": ">=14" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, - "engines": { - "node": ">=12.22" + "dependencies": { + "p-limit": "^2.2.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "engines": { + "node": ">=8" } }, - "node_modules/@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": ">=8" } }, - "node_modules/@inquirer/confirm": { - "version": "3.1.22", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.22.tgz", - "integrity": "sha512-gsAKIOWBm2Q87CDfs9fEo7wJT3fwWIJfnDGMn9Qy74gBnNFOACDNfhUzovubbJjWnKLGBln7/NcSmZwj5DuEXg==", + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, - "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2" - }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/@inquirer/core": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", - "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", - "@types/mute-stream": "^0.0.4", - "@types/node": "^22.1.0", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" }, "engines": { - "node": ">=18" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@inquirer/core/node_modules/ansi-styles": { + "node_modules/@jest/console/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -3040,7 +2593,23 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@inquirer/core/node_modules/color-convert": { + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -3052,258 +2621,266 @@ "node": ">=7.0.0" } }, - "node_modules/@inquirer/core/node_modules/color-name": { + "node_modules/@jest/console/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@inquirer/core/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/@inquirer/core/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@inquirer/core/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, "engines": { "node": ">=8" } }, - "node_modules/@inquirer/core/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/@inquirer/figures": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.5.tgz", - "integrity": "sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/type": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.2.tgz", - "integrity": "sha512-w9qFkumYDCNyDZmNQjf/n6qQuvQ4dMC3BJesY4oF+yr0CxR5vxujflAVeIcS6U336uzi9GM0kAfZlLrZ9UTkpA==", + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, "dependencies": { - "mute-stream": "^1.0.0" + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=18" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" + "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8" + "node": ">=7.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, "dependencies": { - "p-locate": "^4.1.0" + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, "dependencies": { - "p-try": "^2.0.0" + "jest-get-type": "^29.6.3" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, "dependencies": { - "p-limit": "^2.2.0" + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/console": { + "node_modules/@jest/reporters": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", "@types/node": "*", "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", "jest-message-util": "^29.7.0", "jest-util": "^29.7.0", - "slash": "^3.0.0" + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@jest/console/node_modules/ansi-styles": { + "node_modules/@jest/reporters/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -3318,7 +2895,17 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/console/node_modules/chalk": { + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -3334,7 +2921,7 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/console/node_modules/color-convert": { + "node_modules/@jest/reporters/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -3346,13 +2933,34 @@ "node": ">=7.0.0" } }, - "node_modules/@jest/console/node_modules/color-name": { + "node_modules/@jest/reporters/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@jest/console/node_modules/has-flag": { + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", @@ -3361,7 +2969,49 @@ "node": ">=8" } }, - "node_modules/@jest/console/node_modules/supports-color": { + "node_modules/@jest/reporters/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -3373,54 +3023,89 @@ "node": ">=8" } }, - "node_modules/@jest/core": { + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, "dependencies": { "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "dependencies": { "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", + "pirates": "^4.0.4", "slash": "^3.0.0", - "strip-ansi": "^6.0.0" + "write-file-atomic": "^4.0.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } } }, - "node_modules/@jest/core/node_modules/ansi-styles": { + "node_modules/@jest/transform/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -3435,7 +3120,7 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/core/node_modules/chalk": { + "node_modules/@jest/transform/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -3451,7 +3136,7 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/core/node_modules/color-convert": { + "node_modules/@jest/transform/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -3463,13 +3148,19 @@ "node": ">=7.0.0" } }, - "node_modules/@jest/core/node_modules/color-name": { + "node_modules/@jest/transform/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@jest/core/node_modules/has-flag": { + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", @@ -3478,7 +3169,7 @@ "node": ">=8" } }, - "node_modules/@jest/core/node_modules/supports-color": { + "node_modules/@jest/transform/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -3490,1617 +3181,58 @@ "node": ">=8" } }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "jest-mock": "^29.7.0" + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" + "color-convert": "^2.0.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "jest-get-type": "^29.6.3" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/reporters/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters/node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/transform/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/transform/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/transform/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@jsonjoy.com/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", - "dev": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/json-pack": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", - "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", - "dev": true, - "dependencies": { - "@jsonjoy.com/base64": "^1.1.1", - "@jsonjoy.com/util": "^1.1.2", - "hyperdyperid": "^1.2.0", - "thingies": "^1.20.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/util": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", - "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", - "dev": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true - }, - "node_modules/@mdx-js/react": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz", - "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==", - "dev": true, - "dependencies": { - "@types/mdx": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=16", - "react": ">=16" - } - }, - "node_modules/@mswjs/interceptors": { - "version": "0.29.1", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.29.1.tgz", - "integrity": "sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw==", - "dev": true, - "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.2.1", - "strict-event-emitter": "^0.5.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@open-draft/deferred-promise": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", - "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", - "dev": true - }, - "node_modules/@open-draft/logger": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", - "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", - "dev": true, - "dependencies": { - "is-node-process": "^1.2.0", - "outvariant": "^1.4.0" - } - }, - "node_modules/@open-draft/until": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", - "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", - "dev": true - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@remix-run/router": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.0.tgz", - "integrity": "sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@sentry-internal/browser-utils": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.25.0.tgz", - "integrity": "sha512-nlWgp1lVhNQOTUplW85G3qm0fOIgAhJ/sl/31OIuScVrITYhYDF2bO+Zv/jQ8YsdUBAUXqY1tPT9wwPJklnPhw==", - "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" - }, - "engines": { - "node": ">=14.18" - } - }, - "node_modules/@sentry-internal/feedback": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.25.0.tgz", - "integrity": "sha512-327I5XJAFrsgjc5qUKxZ9rff3WNCfGvf1fIii70LQ2YQhQgG4XHZILmkD06ETEyXb+H1tkrNQQEJ1/d4ai+q5g==", - "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" - }, - "engines": { - "node": ">=14.18" - } - }, - "node_modules/@sentry-internal/replay": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.25.0.tgz", - "integrity": "sha512-3f7x8EYthyj157uV9V8vBjun+1gJnHhh2+i0qxYLhMGx7N2Fq0J3Bvvo1rosSg+fYh5HzPNZDufwIRdg5C/MQw==", - "dependencies": { - "@sentry-internal/browser-utils": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" - }, - "engines": { - "node": ">=14.18" - } - }, - "node_modules/@sentry-internal/replay-canvas": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.25.0.tgz", - "integrity": "sha512-dPXlkAbkFL1DBum8rGTaHS+apJKaXEZJF9gLcBBKTruhTCizrugFLxajzIfVSiFVuwNKuJWa2fzhzbeQM0ee7w==", - "dependencies": { - "@sentry-internal/replay": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" - }, - "engines": { - "node": ">=14.18" - } - }, - "node_modules/@sentry/babel-plugin-component-annotate": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.22.0.tgz", - "integrity": "sha512-UzH+NNhgnOo6UFku3C4TEz+pO/yDcIA5FKTJvLbJ7lQwAjsqLs3DZWm4cCA08skICb8mULArF6S/dn5/butVCA==", - "dev": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@sentry/browser": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.25.0.tgz", - "integrity": "sha512-51bdVGXjyooqVGzaSGsnExqRTt9NvZ1zGFsxbbCSXi5UoEFN6zdMUz6jKYsL2K80eeELP2VKOVlobHlEzeJQfw==", - "dependencies": { - "@sentry-internal/browser-utils": "8.25.0", - "@sentry-internal/feedback": "8.25.0", - "@sentry-internal/replay": "8.25.0", - "@sentry-internal/replay-canvas": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" - }, - "engines": { - "node": ">=14.18" - } - }, - "node_modules/@sentry/bundler-plugin-core": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.22.0.tgz", - "integrity": "sha512-/xXN8o7565WMsewBnQFfjm0E5wqhYsegg++HJ5RjrY/cTM4qcd/ven44GEMxqGFJitZizvkk3NHszaHylzcRUw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.18.5", - "@sentry/babel-plugin-component-annotate": "2.22.0", - "@sentry/cli": "^2.33.1", - "dotenv": "^16.3.1", - "find-up": "^5.0.0", - "glob": "^9.3.2", - "magic-string": "0.30.8", - "unplugin": "1.0.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@sentry/bundler-plugin-core/node_modules/glob": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", - "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@sentry/bundler-plugin-core/node_modules/minimatch": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", - "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@sentry/bundler-plugin-core/node_modules/minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@sentry/cli": { - "version": "2.33.1", - "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.33.1.tgz", - "integrity": "sha512-dUlZ4EFh98VFRPJ+f6OW3JEYQ7VvqGNMa0AMcmvk07ePNeK/GicAWmSQE4ZfJTTl80ul6HZw1kY01fGQOQlVRA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.7", - "progress": "^2.0.3", - "proxy-from-env": "^1.1.0", - "which": "^2.0.2" - }, - "bin": { - "sentry-cli": "bin/sentry-cli" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@sentry/cli-darwin": "2.33.1", - "@sentry/cli-linux-arm": "2.33.1", - "@sentry/cli-linux-arm64": "2.33.1", - "@sentry/cli-linux-i686": "2.33.1", - "@sentry/cli-linux-x64": "2.33.1", - "@sentry/cli-win32-i686": "2.33.1", - "@sentry/cli-win32-x64": "2.33.1" - } - }, - "node_modules/@sentry/cli-darwin": { - "version": "2.33.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.33.1.tgz", - "integrity": "sha512-+4/VIx/E1L2hChj5nGf5MHyEPHUNHJ/HoG5RY+B+vyEutGily1c1+DM2bum7RbD0xs6wKLIyup5F02guzSzG8A==", - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-linux-arm": { - "version": "2.33.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.33.1.tgz", - "integrity": "sha512-zbxEvQju+tgNvzTOt635le4kS/Fbm2XC2RtYbCTs034Vb8xjrAxLnK0z1bQnStUV8BkeBHtsNVrG+NSQDym2wg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux", - "freebsd" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-linux-arm64": { - "version": "2.33.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.33.1.tgz", - "integrity": "sha512-DbGV56PRKOLsAZJX27Jt2uZ11QfQEMmWB4cIvxkKcFVE+LJP4MVA+MGGRUL6p+Bs1R9ZUuGbpKGtj0JiG6CoXw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux", - "freebsd" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-linux-i686": { - "version": "2.33.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.33.1.tgz", - "integrity": "sha512-g2LS4oPXkPWOfKWukKzYp4FnXVRRSwBxhuQ9eSw2peeb58ZIObr4YKGOA/8HJRGkooBJIKGaAR2mH2Pk1TKaiA==", - "cpu": [ - "x86", - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux", - "freebsd" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-linux-x64": { - "version": "2.33.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.33.1.tgz", - "integrity": "sha512-IV3dcYV/ZcvO+VGu9U6kuxSdbsV2kzxaBwWUQxtzxJ+cOa7J8Hn1t0koKGtU53JVZNBa06qJWIcqgl4/pCuKIg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux", - "freebsd" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-win32-i686": { - "version": "2.33.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.33.1.tgz", - "integrity": "sha512-F7cJySvkpzIu7fnLKNHYwBzZYYwlhoDbAUnaFX0UZCN+5DNp/5LwTp37a5TWOsmCaHMZT4i9IO4SIsnNw16/zQ==", - "cpu": [ - "x86", - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-win32-x64": { - "version": "2.33.1", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.33.1.tgz", - "integrity": "sha512-8VyRoJqtb2uQ8/bFRKNuACYZt7r+Xx0k2wXRGTyH05lCjAiVIXn7DiS2BxHFty7M1QEWUCMNsb/UC/x/Cu2wuA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/core": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.25.0.tgz", - "integrity": "sha512-7KtglbrW1eX4DOHkf6i4rRIExEf2CgtQ99qZ8gn5FUaAmNMg0rK7bb1yZMx0RZtp5G1TSz/S0jQQgxHWebaEig==", - "dependencies": { - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" - }, - "engines": { - "node": ">=14.18" - } - }, - "node_modules/@sentry/react": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry/react/-/react-8.25.0.tgz", - "integrity": "sha512-A3QeSCJEa+lpo5nh0kxKeqsmnuW2nycKNN/0bpXPv5T5jiEfExSmEBVM0zutrQpf+J0WRIl1AGunUYGPO+GPQg==", - "dependencies": { - "@sentry/browser": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", - "hoist-non-react-statics": "^3.3.2" - }, - "engines": { - "node": ">=14.18" - }, - "peerDependencies": { - "react": "^16.14.0 || 17.x || 18.x || 19.x" - } - }, - "node_modules/@sentry/types": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.25.0.tgz", - "integrity": "sha512-ojim0gDcRhGJPguYrtms4FsprX4xZz3LGNk9Z0hwTbSVEdlhQIInsQ7CYcdM3sjUs+qT7kfpxTRZGUeZNRRJcA==", - "engines": { - "node": ">=14.18" - } - }, - "node_modules/@sentry/utils": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.25.0.tgz", - "integrity": "sha512-mVlkV7S62ZZ2jM38/kOwWx2xoW8fUv2cjw2IwFKoAIPyLBh3mo1WJtvfdtN/rXGjQWZJBKW53EWaWnD00rkjyA==", - "dependencies": { - "@sentry/types": "8.25.0" - }, - "engines": { - "node": ">=14.18" - } - }, - "node_modules/@sentry/webpack-plugin": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-2.22.0.tgz", - "integrity": "sha512-u2brctki0AMCoZksdAConQSYE6PokRVeZ4YYsbnJYkAi0KuaQnczsRwS9e2L0bK2CmZ7QdyYcrjaXHNlXaFDbQ==", - "dev": true, - "dependencies": { - "@sentry/bundler-plugin-core": "2.22.0", - "unplugin": "1.0.1", - "uuid": "^9.0.0" - }, - "engines": { - "node": ">= 14" - }, - "peerDependencies": { - "webpack": ">=4.40.0" - } - }, - "node_modules/@sentry/webpack-plugin/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "node_modules/@sindresorhus/merge-streams": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", - "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@storybook/addon-actions": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.2.9.tgz", - "integrity": "sha512-eh2teOqjga7aoClDVV+/b1gHJqsPwjiU1t+Hg/l4i2CkaBUNdYMEL90nR6fgReOdvvL5YhcPwJ8w38f9TrQcoQ==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "@types/uuid": "^9.0.1", - "dequal": "^2.0.2", - "polished": "^4.2.2", - "uuid": "^9.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-actions/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@storybook/addon-backgrounds": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.2.9.tgz", - "integrity": "sha512-eGmZAd742ORBbQ6JepzBCko/in62T4Xg9j9LVa+Cvz/7L1C/RQSuU6sUwbRAsXaz+PMVDksPDCUUNsXl3zUL7w==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "memoizerific": "^1.11.3", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-controls": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.2.9.tgz", - "integrity": "sha512-vaSE78KOE7SO0GrW4e+mdQphSNpvCX/FGybIRxyaKX9h8smoyUwRNHVyCS3ROHTwH324QWu7GDzsOVrnyXOv0A==", - "dev": true, - "dependencies": { - "dequal": "^2.0.2", - "lodash": "^4.17.21", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-docs": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.2.9.tgz", - "integrity": "sha512-flDOxFIGmXg+6lVdwTLMOKsGob1WrT7rG98mn1SNW0Nxhg3Wg+9pQuq1GLxEzKtAgSflmu+xcBRfYhsogyDXkw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.24.4", - "@mdx-js/react": "^3.0.0", - "@storybook/blocks": "8.2.9", - "@storybook/csf-plugin": "8.2.9", - "@storybook/global": "^5.0.0", - "@storybook/react-dom-shim": "8.2.9", - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "fs-extra": "^11.1.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", - "rehype-external-links": "^3.0.0", - "rehype-slug": "^6.0.0", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-docs/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@storybook/addon-essentials": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.2.9.tgz", - "integrity": "sha512-B2d3eznGZvPIyCVtYX0UhrYcEfK+3Y2sACmEWpSwtk8KXomFEsZnD95m397BYDRw3/X6qeSLWxqgMfqDTEDeMA==", - "dev": true, - "dependencies": { - "@storybook/addon-actions": "8.2.9", - "@storybook/addon-backgrounds": "8.2.9", - "@storybook/addon-controls": "8.2.9", - "@storybook/addon-docs": "8.2.9", - "@storybook/addon-highlight": "8.2.9", - "@storybook/addon-measure": "8.2.9", - "@storybook/addon-outline": "8.2.9", - "@storybook/addon-toolbars": "8.2.9", - "@storybook/addon-viewport": "8.2.9", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-highlight": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.2.9.tgz", - "integrity": "sha512-qdcazeNQoo9QKIq+LJJZZXvFZoLn+i4uhbt1Uf9WtW6oU/c1qxORGVD7jc3zsxbQN9nROVPbJ76sfthogxeqWA==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-interactions": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-8.2.9.tgz", - "integrity": "sha512-oSxBkqpmp1Vm9v/G8mZeFNXD8k6T1NMgzUWzAx7R5m31rfObhoi5Fo1bKQT5BAhSSsdjjd7owTAFKdhwSotSKg==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "@storybook/instrumenter": "8.2.9", - "@storybook/test": "8.2.9", - "polished": "^4.2.2", - "ts-dedent": "^2.2.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-links": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-8.2.9.tgz", - "integrity": "sha512-RhJzUNdDb7lbliwXb64HMwieIeJ+OQ2Ditue1vmSox6NsSd+pshR+okHpAyoP1+fW+dahNENwAS2Kt2QiI78FA==", - "dev": true, - "dependencies": { - "@storybook/csf": "0.1.11", - "@storybook/global": "^5.0.0", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.9" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } - } - }, - "node_modules/@storybook/addon-measure": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.2.9.tgz", - "integrity": "sha512-XUfQtYRKWB2dfbPRmHuos816wt1JrLbtRld5ZC8J8ljeqZ4hFBPTQcgI5GAzZqjQuclLC0KuhlA/0bKxdxMMGA==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "tiny-invariant": "^1.3.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-onboarding": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-onboarding/-/addon-onboarding-8.2.9.tgz", - "integrity": "sha512-9FAWwlnF4JqxOdaZCqe4HeEDj95rqQmITPugPUV3Ra8aJuukPWzlFZgfYubI50TTrnJDAFc8kYeatbxFvoagNQ==", - "dev": true, - "dependencies": { - "react-confetti": "^6.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-outline": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.2.9.tgz", - "integrity": "sha512-p22kI4W7MT0YJOCmg/FfhfH+NpZEDA5tgwstjazSg4ertyhaxziMwWZWiK2JCg0gOAfRJjoYjHz+6/u56iXwgQ==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-toolbars": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.2.9.tgz", - "integrity": "sha512-9LMZZ2jRD86Jh6KXedDbAYs4eHj9HtJA9VhSEE2wiqMGwXozpySi7B1GWniNzmFfcgMQ4JHfmD/OrBVTK7Ca/w==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-viewport": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.2.9.tgz", - "integrity": "sha512-lyM24+DJEt8R0YZkJKee34NQWv0REACU6lYDalqJNdKS1sEwzLGWxg1hZXnw2JFdBID9NGVvyYU2w6LDozOB0g==", - "dev": true, - "dependencies": { - "memoizerific": "^1.11.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/addon-webpack5-compiler-swc": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-webpack5-compiler-swc/-/addon-webpack5-compiler-swc-1.0.5.tgz", - "integrity": "sha512-1NlM3noit2vA22OyWb8Ma2lhcEKCS1Snv2kr+EkaVABUqNDfVc9AD/GgYQhF7F/2CoF5N2JU7uzXDzFHd5TzZg==", - "dev": true, - "dependencies": { - "@swc/core": "^1.7.3", - "swc-loader": "^0.2.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@storybook/blocks": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.2.9.tgz", - "integrity": "sha512-5276q/s/UL8arwftuBXovUNHqYo/HPQFMGXEmjVVAMXUyFjzEAfKj3+xU897J6AuL+7XVZG32WnqA+X6LJMrcQ==", - "dev": true, - "dependencies": { - "@storybook/csf": "0.1.11", - "@storybook/global": "^5.0.0", - "@storybook/icons": "^1.2.5", - "@types/lodash": "^4.14.167", - "color-convert": "^2.0.1", - "dequal": "^2.0.2", - "lodash": "^4.17.21", - "markdown-to-jsx": "^7.4.5", - "memoizerific": "^1.11.3", - "polished": "^4.2.2", - "react-colorful": "^5.1.2", - "telejson": "^7.2.0", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.9" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/@storybook/blocks/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@storybook/blocks/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@storybook/builder-webpack5": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-8.2.9.tgz", - "integrity": "sha512-D3oYk4LkteWZ3QLcdUTu/0rUvVNUp/bWwEKAycZDr2uFCOhv8VoS2/l/TaHjn3wpyWpVVKS6GgdP72K++YVufg==", - "dev": true, - "dependencies": { - "@storybook/core-webpack": "8.2.9", - "@types/node": "^18.0.0", - "@types/semver": "^7.3.4", - "browser-assert": "^1.2.1", - "case-sensitive-paths-webpack-plugin": "^2.4.0", - "cjs-module-lexer": "^1.2.3", - "constants-browserify": "^1.0.0", - "css-loader": "^6.7.1", - "es-module-lexer": "^1.5.0", - "express": "^4.19.2", - "fork-ts-checker-webpack-plugin": "^8.0.0", - "fs-extra": "^11.1.0", - "html-webpack-plugin": "^5.5.0", - "magic-string": "^0.30.5", - "path-browserify": "^1.0.1", - "process": "^0.11.10", - "semver": "^7.3.7", - "style-loader": "^3.3.1", - "terser-webpack-plugin": "^5.3.1", - "ts-dedent": "^2.0.0", - "url": "^0.11.0", - "util": "^0.12.4", - "util-deprecate": "^1.0.2", - "webpack": "5", - "webpack-dev-middleware": "^6.1.2", - "webpack-hot-middleware": "^2.25.1", - "webpack-virtual-modules": "^0.6.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/@types/node": { - "version": "18.19.50", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz", - "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { "color-name": "~1.1.4" @@ -5109,85 +3241,13 @@ "node": ">=7.0.0" } }, - "node_modules/@storybook/builder-webpack5/node_modules/color-name": { + "node_modules/@jest/types/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@storybook/builder-webpack5/node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/fork-ts-checker-webpack-plugin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz", - "integrity": "sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "cosmiconfig": "^7.0.1", - "deepmerge": "^4.2.2", - "fs-extra": "^10.0.0", - "memfs": "^3.4.1", - "minimatch": "^3.0.4", - "node-abort-controller": "^3.0.1", - "schema-utils": "^3.1.1", - "semver": "^7.3.5", - "tapable": "^2.2.1" - }, - "engines": { - "node": ">=12.13.0", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "typescript": ">3.6.0", - "webpack": "^5.11.0" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/has-flag": { + "node_modules/@jest/types/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", @@ -5196,37 +3256,7 @@ "node": ">=8" } }, - "node_modules/@storybook/builder-webpack5/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/@storybook/builder-webpack5/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/supports-color": { + "node_modules/@jest/types/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -5238,937 +3268,627 @@ "node": ">=8" } }, - "node_modules/@storybook/builder-webpack5/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.3.tgz", - "integrity": "sha512-A4ChP0Qj8oGociTs6UdlRUGANIGrCDL3y+pmQMc+dSsraXHCatFpmMey4mYELA+juqwUqwQsUgJJISXl1KWmiw==", - "dev": true, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.12", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - } + "node": ">=6.0.0" } }, - "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=6.0.0" } }, - "node_modules/@storybook/builder-webpack5/node_modules/webpack-virtual-modules": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", - "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", - "dev": true - }, - "node_modules/@storybook/codemod": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-8.2.9.tgz", - "integrity": "sha512-3yRx1lFMm1FXWVv+CKDiYM4gOQPEfpcZAQrjfcumxSDUrB091pnU1PeI92Prj3vCdi4+0oPNuN4yDGNUYTMP/A==", - "dev": true, - "dependencies": { - "@babel/core": "^7.24.4", - "@babel/preset-env": "^7.24.4", - "@babel/types": "^7.24.0", - "@storybook/core": "8.2.9", - "@storybook/csf": "0.1.11", - "@types/cross-spawn": "^6.0.2", - "cross-spawn": "^7.0.3", - "globby": "^14.0.1", - "jscodeshift": "^0.15.1", - "lodash": "^4.17.21", - "prettier": "^3.1.1", - "recast": "^0.23.5", - "tiny-invariant": "^1.3.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@storybook/codemod/node_modules/globby": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", - "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "dependencies": { - "@sindresorhus/merge-streams": "^2.1.0", - "fast-glob": "^3.3.2", - "ignore": "^5.2.4", - "path-type": "^5.0.0", - "slash": "^5.1.0", - "unicorn-magic": "^0.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/@storybook/codemod/node_modules/path-type": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", - "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@storybook/codemod/node_modules/slash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "dev": true, "engines": { - "node": ">=14.16" + "node": ">=10.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@storybook/components": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.2.9.tgz", - "integrity": "sha512-OkkcZ/f/6o3GdFEEK9ZHKIGHWUHmavZUYs5xaSgU64bOrA2aqEFtfeWWitZYTv3Euhk8MVLWfyEMDfez0AlvDg==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "type": "github", + "url": "https://github.com/sponsors/streamich" }, "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/core": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.2.9.tgz", - "integrity": "sha512-wSER8FpA6Il/jPyDfKm3yohxDtuhisNPTonMVzd3ulNWR4zERLddyO3HrHJJwdqYHLNk4SBFzwMGpQZVws1y0w==", - "dev": true, - "dependencies": { - "@storybook/csf": "0.1.11", - "@types/express": "^4.17.21", - "@types/node": "^18.0.0", - "browser-assert": "^1.2.1", - "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0", - "esbuild-register": "^3.5.0", - "express": "^4.19.2", - "process": "^0.11.10", - "recast": "^0.23.5", - "util": "^0.12.4", - "ws": "^8.2.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "tslib": "2" } }, - "node_modules/@storybook/core-webpack": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.2.9.tgz", - "integrity": "sha512-6yL1su+d8IOTU+UkZqM9SeBcVc/G6vUHLsMdlWNyVtRus2JTMmT0K0/ll56jrm/ym0y98cxUOA1jsImkBubP2Q==", + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", + "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", "dev": true, "dependencies": { - "@types/node": "^18.0.0", - "ts-dedent": "^2.0.0" + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "type": "github", + "url": "https://github.com/sponsors/streamich" }, "peerDependencies": { - "storybook": "^8.2.9" + "tslib": "2" } }, - "node_modules/@storybook/core-webpack/node_modules/@types/node": { - "version": "18.19.50", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz", - "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==", + "node_modules/@jsonjoy.com/util": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", + "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", "dev": true, - "dependencies": { - "undici-types": "~5.26.4" + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@storybook/core-webpack/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", "dev": true }, - "node_modules/@storybook/core/node_modules/@types/node": { - "version": "18.19.50", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz", - "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==", + "node_modules/@mswjs/interceptors": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.29.1.tgz", + "integrity": "sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw==", "dev": true, "dependencies": { - "undici-types": "~5.26.4" + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.2.1", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" } }, - "node_modules/@storybook/core/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/@storybook/csf": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.11.tgz", - "integrity": "sha512-dHYFQH3mA+EtnCkHXzicbLgsvzYjcDJ1JWsogbItZogkPHgSJM/Wr71uMkcvw8v9mmCyP4NpXJuu6bPoVsOnzg==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "dependencies": { - "type-fest": "^2.19.0" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/@storybook/csf-plugin": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.2.9.tgz", - "integrity": "sha512-QQCFb3g12VQQEraDV1UfCmniGhQZKyT6oEt1Im6dzzPJj9NQk+6BjWoDep33CZhBHWoLryrMQd2fjuHxnFRNEA==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "dependencies": { - "unplugin": "^1.3.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" + "engines": { + "node": ">= 8" } }, - "node_modules/@storybook/csf-plugin/node_modules/unplugin": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.13.1.tgz", - "integrity": "sha512-6Kq1iSSwg7KyjcThRUks9LuqDAKvtnioxbL9iEtB9ctTyBA5OmrB8gZd/d225VJu1w3UpUsKV7eGrvf59J7+VA==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "acorn": "^8.12.1", - "webpack-virtual-modules": "^0.6.2" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "webpack-sources": "^3" - }, - "peerDependenciesMeta": { - "webpack-sources": { - "optional": true - } + "node": ">= 8" } }, - "node_modules/@storybook/csf-plugin/node_modules/webpack-virtual-modules": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", - "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", "dev": true }, - "node_modules/@storybook/csf/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" } }, - "node_modules/@storybook/global": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", - "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", "dev": true }, - "node_modules/@storybook/icons": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.2.10.tgz", - "integrity": "sha512-310apKdDcjbbX2VSLWPwhEwAgjxTzVagrwucVZIdGPErwiAppX8KvBuWZgPo+rQLVrtH8S+pw1dbUwjcE6d7og==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "optional": true, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "node": ">=14" } }, - "node_modules/@storybook/instrumenter": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.2.9.tgz", - "integrity": "sha512-+DNjTbsMzlDggsvkhRuOy7aGvQJ4oLCPgunP5Se/3yBjG+M2bYDa0EmC5jC2nwZ3ffpuvbzaVe7fWf7R8W9F2Q==", + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "@vitest/utils": "^1.3.1", - "util": "^0.12.4" + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" + "url": "https://opencollective.com/unts" } }, - "node_modules/@storybook/manager-api": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.2.9.tgz", - "integrity": "sha512-mkYvUlfqDw+0WbxIynh5TcrotmoXlumEsOA4+45zuNea8XpEgj5cNBUCnmfEO6yQ85swqkS8YYbMpg1cZyu/Vw==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" + "node_modules/@remix-run/router": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.0.tgz", + "integrity": "sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==", + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@storybook/preset-react-webpack": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-8.2.9.tgz", - "integrity": "sha512-uBLsUfwymWXGmfN/0vB7gLCC0CWDHc778605SWxakqFx7wGF1FZUW4R46qbDFrHTaKh+bundseRdy5/uklksLQ==", - "dev": true, + "node_modules/@sentry-internal/browser-utils": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.25.0.tgz", + "integrity": "sha512-nlWgp1lVhNQOTUplW85G3qm0fOIgAhJ/sl/31OIuScVrITYhYDF2bO+Zv/jQ8YsdUBAUXqY1tPT9wwPJklnPhw==", "dependencies": { - "@storybook/core-webpack": "8.2.9", - "@storybook/react": "8.2.9", - "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.0c3f3b7.0", - "@types/node": "^18.0.0", - "@types/semver": "^7.3.4", - "find-up": "^5.0.0", - "fs-extra": "^11.1.0", - "magic-string": "^0.30.5", - "react-docgen": "^7.0.0", - "resolve": "^1.22.8", - "semver": "^7.3.7", - "tsconfig-paths": "^4.2.0", - "webpack": "5" + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" }, "engines": { - "node": ">=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.9" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@storybook/preset-react-webpack/node_modules/@types/node": { - "version": "18.19.50", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz", - "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" + "node": ">=14.18" } }, - "node_modules/@storybook/preset-react-webpack/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, + "node_modules/@sentry-internal/feedback": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.25.0.tgz", + "integrity": "sha512-327I5XJAFrsgjc5qUKxZ9rff3WNCfGvf1fIii70LQ2YQhQgG4XHZILmkD06ETEyXb+H1tkrNQQEJ1/d4ai+q5g==", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" }, "engines": { - "node": ">=14.14" + "node": ">=14.18" } }, - "node_modules/@storybook/preset-react-webpack/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node_modules/@sentry-internal/replay": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.25.0.tgz", + "integrity": "sha512-3f7x8EYthyj157uV9V8vBjun+1gJnHhh2+i0qxYLhMGx7N2Fq0J3Bvvo1rosSg+fYh5HzPNZDufwIRdg5C/MQw==", + "dependencies": { + "@sentry-internal/browser-utils": "8.25.0", + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" }, "engines": { - "node": ">=10" + "node": ">=14.18" } }, - "node_modules/@storybook/preset-react-webpack/node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, + "node_modules/@sentry-internal/replay-canvas": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.25.0.tgz", + "integrity": "sha512-dPXlkAbkFL1DBum8rGTaHS+apJKaXEZJF9gLcBBKTruhTCizrugFLxajzIfVSiFVuwNKuJWa2fzhzbeQM0ee7w==", "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "@sentry-internal/replay": "8.25.0", + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" }, "engines": { - "node": ">=6" + "node": ">=14.18" } }, - "node_modules/@storybook/preset-react-webpack/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/@storybook/preview-api": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.2.9.tgz", - "integrity": "sha512-D8/t+a78OJqQAcT/ABa1C4YM/OaLGQ9IvCsp3Q9ruUqDCwuZBj8bG3D4477dlY4owX2ycC0rWYu3VvuK0EmJjA==", + "node_modules/@sentry/babel-plugin-component-annotate": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.22.0.tgz", + "integrity": "sha512-UzH+NNhgnOo6UFku3C4TEz+pO/yDcIA5FKTJvLbJ7lQwAjsqLs3DZWm4cCA08skICb8mULArF6S/dn5/butVCA==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" - } - }, - "node_modules/@storybook/react": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.2.9.tgz", - "integrity": "sha512-F2xZcTDxxjpbqt7eP8rEHmlksiKmE/qtPusEWEY4N4jK01kN+ncxSl8gkJpUohMEmAnVC5t/1v/sU57xv1DYpg==", - "dev": true, - "dependencies": { - "@storybook/components": "^8.2.9", - "@storybook/global": "^5.0.0", - "@storybook/manager-api": "^8.2.9", - "@storybook/preview-api": "^8.2.9", - "@storybook/react-dom-shim": "8.2.9", - "@storybook/theming": "^8.2.9", - "@types/escodegen": "^0.0.6", - "@types/estree": "^0.0.51", - "@types/node": "^18.0.0", - "acorn": "^7.4.1", - "acorn-jsx": "^5.3.1", - "acorn-walk": "^7.2.0", - "escodegen": "^2.1.0", - "html-tags": "^3.1.0", - "lodash": "^4.17.21", - "prop-types": "^15.7.2", - "react-element-to-jsx-string": "^15.0.0", - "semver": "^7.3.7", - "ts-dedent": "^2.0.0", - "type-fest": "~2.19", - "util-deprecate": "^1.0.2" - }, "engines": { - "node": ">=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.9", - "typescript": ">= 4.2.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@storybook/react-docgen-typescript-plugin": { - "version": "1.0.6--canary.9.0c3f3b7.0", - "resolved": "https://registry.npmjs.org/@storybook/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-1.0.6--canary.9.0c3f3b7.0.tgz", - "integrity": "sha512-KUqXC3oa9JuQ0kZJLBhVdS4lOneKTOopnNBK4tUAgoxWQ3u/IjzdueZjFr7gyBrXMoU6duutk3RQR9u8ZpYJ4Q==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "endent": "^2.0.1", - "find-cache-dir": "^3.3.1", - "flat-cache": "^3.0.4", - "micromatch": "^4.0.2", - "react-docgen-typescript": "^2.2.2", - "tslib": "^2.0.0" - }, - "peerDependencies": { - "typescript": ">= 4.x", - "webpack": ">= 4" + "node": ">= 14" } }, - "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "node_modules/@sentry/browser": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.25.0.tgz", + "integrity": "sha512-51bdVGXjyooqVGzaSGsnExqRTt9NvZ1zGFsxbbCSXi5UoEFN6zdMUz6jKYsL2K80eeELP2VKOVlobHlEzeJQfw==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@sentry-internal/browser-utils": "8.25.0", + "@sentry-internal/feedback": "8.25.0", + "@sentry-internal/replay": "8.25.0", + "@sentry-internal/replay-canvas": "8.25.0", + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" + }, + "engines": { + "node": ">=14.18" } }, - "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "node_modules/@sentry/bundler-plugin-core": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.22.0.tgz", + "integrity": "sha512-/xXN8o7565WMsewBnQFfjm0E5wqhYsegg++HJ5RjrY/cTM4qcd/ven44GEMxqGFJitZizvkk3NHszaHylzcRUw==", "dev": true, "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "@babel/core": "^7.18.5", + "@sentry/babel-plugin-component-annotate": "2.22.0", + "@sentry/cli": "^2.33.1", + "dotenv": "^16.3.1", + "find-up": "^5.0.0", + "glob": "^9.3.2", + "magic-string": "0.30.8", + "unplugin": "1.0.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">= 14" } }, - "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/@sentry/bundler-plugin-core/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@sentry/bundler-plugin-core/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" - } - }, - "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@storybook/react-dom-shim": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.2.9.tgz", - "integrity": "sha512-uCAjSQEsNk8somVn1j/I1G9G/uUax5byHseIIV0Eq3gVXttGd7gaWcP+TDHtqIaenWHx4l+hCSuCesxiLWmx4Q==", + "node_modules/@sentry/bundler-plugin-core/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.9" + "engines": { + "node": ">=8" } }, - "node_modules/@storybook/react-webpack5": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/react-webpack5/-/react-webpack5-8.2.9.tgz", - "integrity": "sha512-c5udaEIFFlBfOQJlPsJvrhyK02B3ltZ86SS0j5bhOa6UgqYOo+KtKaVyegXWgsRw8vVO9ZdmXCfwVvFsHkgJdA==", + "node_modules/@sentry/cli": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.33.1.tgz", + "integrity": "sha512-dUlZ4EFh98VFRPJ+f6OW3JEYQ7VvqGNMa0AMcmvk07ePNeK/GicAWmSQE4ZfJTTl80ul6HZw1kY01fGQOQlVRA==", "dev": true, + "hasInstallScript": true, "dependencies": { - "@storybook/builder-webpack5": "8.2.9", - "@storybook/preset-react-webpack": "8.2.9", - "@storybook/react": "8.2.9", - "@types/node": "^18.0.0" - }, - "engines": { - "node": ">=18.0.0" + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.7", + "progress": "^2.0.3", + "proxy-from-env": "^1.1.0", + "which": "^2.0.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "bin": { + "sentry-cli": "bin/sentry-cli" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.9", - "typescript": ">= 4.2.x" + "engines": { + "node": ">= 10" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@storybook/react-webpack5/node_modules/@types/node": { - "version": "18.19.50", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz", - "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@storybook/react-webpack5/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/@storybook/react/node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "node_modules/@storybook/react/node_modules/@types/node": { - "version": "18.19.50", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz", - "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" + "optionalDependencies": { + "@sentry/cli-darwin": "2.33.1", + "@sentry/cli-linux-arm": "2.33.1", + "@sentry/cli-linux-arm64": "2.33.1", + "@sentry/cli-linux-i686": "2.33.1", + "@sentry/cli-linux-x64": "2.33.1", + "@sentry/cli-win32-i686": "2.33.1", + "@sentry/cli-win32-x64": "2.33.1" } }, - "node_modules/@storybook/react/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/@sentry/cli-darwin": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.33.1.tgz", + "integrity": "sha512-+4/VIx/E1L2hChj5nGf5MHyEPHUNHJ/HoG5RY+B+vyEutGily1c1+DM2bum7RbD0xs6wKLIyup5F02guzSzG8A==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=0.4.0" + "node": ">=10" } }, - "node_modules/@storybook/react/node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "node_modules/@sentry/cli-linux-arm": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.33.1.tgz", + "integrity": "sha512-zbxEvQju+tgNvzTOt635le4kS/Fbm2XC2RtYbCTs034Vb8xjrAxLnK0z1bQnStUV8BkeBHtsNVrG+NSQDym2wg==", + "cpu": [ + "arm" + ], "dev": true, + "optional": true, + "os": [ + "linux", + "freebsd" + ], "engines": { - "node": ">=0.4.0" + "node": ">=10" } }, - "node_modules/@storybook/react/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "node_modules/@sentry/cli-linux-arm64": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.33.1.tgz", + "integrity": "sha512-DbGV56PRKOLsAZJX27Jt2uZ11QfQEMmWB4cIvxkKcFVE+LJP4MVA+MGGRUL6p+Bs1R9ZUuGbpKGtj0JiG6CoXw==", + "cpu": [ + "arm64" + ], "dev": true, - "bin": { - "semver": "bin/semver.js" - }, + "optional": true, + "os": [ + "linux", + "freebsd" + ], "engines": { "node": ">=10" } }, - "node_modules/@storybook/react/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "node_modules/@sentry/cli-linux-i686": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.33.1.tgz", + "integrity": "sha512-g2LS4oPXkPWOfKWukKzYp4FnXVRRSwBxhuQ9eSw2peeb58ZIObr4YKGOA/8HJRGkooBJIKGaAR2mH2Pk1TKaiA==", + "cpu": [ + "x86", + "ia32" + ], "dev": true, + "optional": true, + "os": [ + "linux", + "freebsd" + ], "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=10" } }, - "node_modules/@storybook/react/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/@storybook/test": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.2.9.tgz", - "integrity": "sha512-O5JZ5S8UVVR7V0ru5AiF/uRO+srAVwji0Iik7ihy8gw3V91WQNMmJh2KkdhG0R1enYeBsYZlipOm+AW7f/MmOA==", + "node_modules/@sentry/cli-linux-x64": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.33.1.tgz", + "integrity": "sha512-IV3dcYV/ZcvO+VGu9U6kuxSdbsV2kzxaBwWUQxtzxJ+cOa7J8Hn1t0koKGtU53JVZNBa06qJWIcqgl4/pCuKIg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@storybook/csf": "0.1.11", - "@storybook/instrumenter": "8.2.9", - "@testing-library/dom": "10.1.0", - "@testing-library/jest-dom": "6.4.5", - "@testing-library/user-event": "14.5.2", - "@vitest/expect": "1.6.0", - "@vitest/spy": "1.6.0", - "util": "^0.12.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" + "optional": true, + "os": [ + "linux", + "freebsd" + ], + "engines": { + "node": ">=10" } }, - "node_modules/@storybook/test/node_modules/@testing-library/dom": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.1.0.tgz", - "integrity": "sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==", + "node_modules/@sentry/cli-win32-i686": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.33.1.tgz", + "integrity": "sha512-F7cJySvkpzIu7fnLKNHYwBzZYYwlhoDbAUnaFX0UZCN+5DNp/5LwTp37a5TWOsmCaHMZT4i9IO4SIsnNw16/zQ==", + "cpu": [ + "x86", + "ia32" + ], "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=18" + "node": ">=10" } }, - "node_modules/@storybook/test/node_modules/@testing-library/jest-dom": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz", - "integrity": "sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==", + "node_modules/@sentry/cli-win32-x64": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.33.1.tgz", + "integrity": "sha512-8VyRoJqtb2uQ8/bFRKNuACYZt7r+Xx0k2wXRGTyH05lCjAiVIXn7DiS2BxHFty7M1QEWUCMNsb/UC/x/Cu2wuA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@adobe/css-tools": "^4.3.2", - "@babel/runtime": "^7.9.2", - "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" - }, - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" - }, - "peerDependencies": { - "@jest/globals": ">= 28", - "@types/bun": "latest", - "@types/jest": ">= 28", - "jest": ">= 28", - "vitest": ">= 0.32" - }, - "peerDependenciesMeta": { - "@jest/globals": { - "optional": true - }, - "@types/bun": { - "optional": true - }, - "@types/jest": { - "optional": true - }, - "jest": { - "optional": true - }, - "vitest": { - "optional": true - } + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" } }, - "node_modules/@storybook/test/node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, + "node_modules/@sentry/core": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.25.0.tgz", + "integrity": "sha512-7KtglbrW1eX4DOHkf6i4rRIExEf2CgtQ99qZ8gn5FUaAmNMg0rK7bb1yZMx0RZtp5G1TSz/S0jQQgxHWebaEig==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" }, "engines": { - "node": ">=8" + "node": ">=14.18" } }, - "node_modules/@storybook/test/node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", - "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "dev": true - }, - "node_modules/@storybook/test/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/@sentry/react": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry/react/-/react-8.25.0.tgz", + "integrity": "sha512-A3QeSCJEa+lpo5nh0kxKeqsmnuW2nycKNN/0bpXPv5T5jiEfExSmEBVM0zutrQpf+J0WRIl1AGunUYGPO+GPQg==", "dependencies": { - "color-convert": "^2.0.1" + "@sentry/browser": "8.25.0", + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0", + "hoist-non-react-statics": "^3.3.2" }, "engines": { - "node": ">=8" + "node": ">=14.18" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "react": "^16.14.0 || 17.x || 18.x || 19.x" } }, - "node_modules/@storybook/test/node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "dependencies": { - "dequal": "^2.0.3" + "node_modules/@sentry/types": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.25.0.tgz", + "integrity": "sha512-ojim0gDcRhGJPguYrtms4FsprX4xZz3LGNk9Z0hwTbSVEdlhQIInsQ7CYcdM3sjUs+qT7kfpxTRZGUeZNRRJcA==", + "engines": { + "node": ">=14.18" } }, - "node_modules/@storybook/test/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/@sentry/utils": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.25.0.tgz", + "integrity": "sha512-mVlkV7S62ZZ2jM38/kOwWx2xoW8fUv2cjw2IwFKoAIPyLBh3mo1WJtvfdtN/rXGjQWZJBKW53EWaWnD00rkjyA==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@sentry/types": "8.25.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=14.18" } }, - "node_modules/@storybook/test/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@sentry/webpack-plugin": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-2.22.0.tgz", + "integrity": "sha512-u2brctki0AMCoZksdAConQSYE6PokRVeZ4YYsbnJYkAi0KuaQnczsRwS9e2L0bK2CmZ7QdyYcrjaXHNlXaFDbQ==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@sentry/bundler-plugin-core": "2.22.0", + "unplugin": "1.0.1", + "uuid": "^9.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">= 14" + }, + "peerDependencies": { + "webpack": ">=4.40.0" } }, - "node_modules/@storybook/test/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@storybook/test/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@sentry/webpack-plugin/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", "dev": true, - "engines": { - "node": ">=8" + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" } }, - "node_modules/@storybook/test/node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "type-detect": "4.0.8" } }, - "node_modules/@storybook/test/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "dependencies": { + "@sinonjs/commons": "^3.0.0" } }, - "node_modules/@storybook/test/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/@storybook/test/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/@storybook/addon-webpack5-compiler-swc": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@storybook/addon-webpack5-compiler-swc/-/addon-webpack5-compiler-swc-1.0.5.tgz", + "integrity": "sha512-1NlM3noit2vA22OyWb8Ma2lhcEKCS1Snv2kr+EkaVABUqNDfVc9AD/GgYQhF7F/2CoF5N2JU7uzXDzFHd5TzZg==", "dependencies": { - "has-flag": "^4.0.0" + "@swc/core": "^1.7.3", + "swc-loader": "^0.2.3" }, "engines": { - "node": ">=8" - } - }, - "node_modules/@storybook/theming": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.2.9.tgz", - "integrity": "sha512-OL0NFvowPX85N5zIYdgeKKaFm7V4Vgtci093vL3cDZT13LGH6GuEzJKkUFGuUGNPFlJc+EgTj0o6PYKrOLyQ6w==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.9" + "node": ">=18" } }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", - "dev": true, "engines": { "node": ">=14" }, @@ -6184,7 +3904,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", - "dev": true, "engines": { "node": ">=14" }, @@ -6200,7 +3919,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", - "dev": true, "engines": { "node": ">=14" }, @@ -6216,7 +3934,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", - "dev": true, "engines": { "node": ">=14" }, @@ -6232,7 +3949,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", - "dev": true, "engines": { "node": ">=14" }, @@ -6248,7 +3964,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", - "dev": true, "engines": { "node": ">=14" }, @@ -6264,7 +3979,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", - "dev": true, "engines": { "node": ">=14" }, @@ -6280,7 +3994,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", - "dev": true, "engines": { "node": ">=12" }, @@ -6296,7 +4009,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", - "dev": true, "dependencies": { "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", @@ -6322,7 +4034,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", - "dev": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -6342,7 +4053,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", - "dev": true, "dependencies": { "@babel/types": "^7.21.3", "entities": "^4.4.0" @@ -6359,7 +4069,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", - "dev": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -6381,7 +4090,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", - "dev": true, "dependencies": { "cosmiconfig": "^8.1.3", "deepmerge": "^4.3.1", @@ -6402,7 +4110,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", - "dev": true, "dependencies": { "@babel/core": "^7.21.3", "@babel/plugin-transform-react-constant-elements": "^7.21.3", @@ -6425,7 +4132,6 @@ "version": "1.7.14", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.14.tgz", "integrity": "sha512-9aeXeifnyuvc2pcuuhPQgVUwdpGEzZ+9nJu0W8/hNl/aESFsJGR5i9uQJRGu0atoNr01gK092fvmqMmQAPcKow==", - "dev": true, "hasInstallScript": true, "dependencies": { "@swc/counter": "^0.1.3", @@ -6466,7 +4172,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -6482,7 +4187,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -6498,7 +4202,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -6514,7 +4217,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -6530,7 +4232,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -6546,7 +4247,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -6562,7 +4262,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -6578,7 +4277,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -6594,7 +4292,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -6610,7 +4307,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -6622,14 +4318,12 @@ "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "dev": true + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" }, "node_modules/@swc/types": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz", "integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==", - "dev": true, "dependencies": { "@swc/counter": "^0.1.3" } @@ -6936,19 +4630,6 @@ } } }, - "node_modules/@testing-library/user-event": { - "version": "14.5.2", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", - "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", - "dev": true, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -6962,7 +4643,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true, "engines": { "node": ">=10.13.0" } @@ -7082,21 +4762,6 @@ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", "dev": true }, - "node_modules/@types/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/doctrine": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", - "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", - "dev": true - }, "node_modules/@types/dotenv-webpack": { "version": "7.0.7", "resolved": "https://registry.npmjs.org/@types/dotenv-webpack/-/dotenv-webpack-7.0.7.tgz", @@ -7108,18 +4773,6 @@ "webpack": "^5" } }, - "node_modules/@types/emscripten": { - "version": "1.39.13", - "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.13.tgz", - "integrity": "sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==", - "dev": true - }, - "node_modules/@types/escodegen": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.6.tgz", - "integrity": "sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==", - "dev": true - }, "node_modules/@types/eslint": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", @@ -7179,15 +4832,6 @@ "@types/node": "*" } }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dev": true, - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -7266,18 +4910,6 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "node_modules/@types/lodash": { - "version": "4.17.7", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", - "integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==", - "dev": true - }, - "node_modules/@types/mdx": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", - "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", - "dev": true - }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -7362,24 +4994,12 @@ "@types/react": "*" } }, - "node_modules/@types/resolve": { - "version": "1.20.6", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", - "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==", - "dev": true - }, "node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", "dev": true }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -7459,18 +5079,6 @@ "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", "dev": true }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "dev": true - }, - "node_modules/@types/uuid": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", - "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", - "dev": true - }, "node_modules/@types/wrap-ansi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", @@ -7705,54 +5313,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/@vitest/expect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", - "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", - "dev": true, - "dependencies": { - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", - "chai": "^4.3.10" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", - "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", - "dev": true, - "dependencies": { - "tinyspy": "^2.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", - "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", - "dev": true, - "dependencies": { - "diff-sequences": "^29.6.3", - "estree-walker": "^3.0.3", - "loupe": "^2.3.7", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@webassemblyjs/ast": { @@ -7957,44 +5518,6 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, - "node_modules/@yarnpkg/fslib": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@yarnpkg/fslib/-/fslib-2.10.3.tgz", - "integrity": "sha512-41H+Ga78xT9sHvWLlFOZLIhtU6mTGZ20pZ29EiZa97vnxdohJD2AF42rCoAoWfqUz486xY6fhjMH+DYEM9r14A==", - "dev": true, - "dependencies": { - "@yarnpkg/libzip": "^2.3.0", - "tslib": "^1.13.0" - }, - "engines": { - "node": ">=12 <14 || 14.2 - 14.9 || >14.10.0" - } - }, - "node_modules/@yarnpkg/fslib/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/@yarnpkg/libzip": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/libzip/-/libzip-2.3.0.tgz", - "integrity": "sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==", - "dev": true, - "dependencies": { - "@types/emscripten": "^1.39.6", - "tslib": "^1.13.0" - }, - "engines": { - "node": ">=12 <14 || 14.2 - 14.9 || >14.10.0" - } - }, - "node_modules/@yarnpkg/libzip/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -8266,8 +5789,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/aria-query": { "version": "5.1.3", @@ -8461,27 +5983,6 @@ "node": ">=0.8" } }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/ast-types": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", - "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", - "dev": true, - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/ast-types-flow": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", @@ -8566,15 +6067,6 @@ "deep-equal": "^2.0.5" } }, - "node_modules/babel-core": { - "version": "7.0.0-bridge.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", - "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", - "dev": true, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -8746,7 +6238,6 @@ "version": "0.4.11", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.6.2", @@ -8760,7 +6251,6 @@ "version": "0.10.6", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", - "dev": true, "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.2", "core-js-compat": "^3.38.0" @@ -8773,7 +6263,6 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", - "dev": true, "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.2" }, @@ -8882,17 +6371,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, "node_modules/blob-util": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", @@ -8966,8 +6444,7 @@ "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, "node_modules/brace-expansion": { "version": "2.0.1", @@ -8990,17 +6467,10 @@ "node": ">=8" } }, - "node_modules/browser-assert": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", - "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", - "dev": true - }, "node_modules/browserslist": { "version": "4.23.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -9162,7 +6632,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, "engines": { "node": ">=10" }, @@ -9174,7 +6643,6 @@ "version": "1.0.30001649", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001649.tgz", "integrity": "sha512-fJegqZZ0ZX8HOWr6rcafGr72+xcgJKI9oWfDW5DrD7ExUtgZC7a7R7ZYmZqplh7XDocFdGeIFn7roAxhOeYrPQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -9190,48 +6658,12 @@ } ] }, - "node_modules/case-sensitive-paths-webpack-plugin": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", - "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, - "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai/node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -9262,18 +6694,6 @@ "node": ">=10" } }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, "node_modules/check-more-types": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", @@ -9319,38 +6739,6 @@ "node": ">= 6" } }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chromatic": { - "version": "11.7.1", - "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-11.7.1.tgz", - "integrity": "sha512-LvgPimdQdnQB07ZDxLEC2KtxgYeqTw0X71GA7fi3zhgtKLxZcE+BSZ/5I9rrQp1V8ydmfElfw0ZwnUH4fVgUAQ==", - "dev": true, - "bin": { - "chroma": "dist/bin.js", - "chromatic": "dist/bin.js", - "chromatic-cli": "dist/bin.js" - }, - "peerDependencies": { - "@chromatic-com/cypress": "^0.*.* || ^1.0.0", - "@chromatic-com/playwright": "^0.*.* || ^1.0.0" - }, - "peerDependenciesMeta": { - "@chromatic-com/cypress": { - "optional": true - }, - "@chromatic-com/playwright": { - "optional": true - } - } - }, "node_modules/chrome-trace-event": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", @@ -9375,15 +6763,6 @@ "node": ">=8" } }, - "node_modules/citty": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", - "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", - "dev": true, - "dependencies": { - "consola": "^3.2.3" - } - }, "node_modules/cjs-module-lexer": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", @@ -9608,15 +6987,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -9696,18 +7066,6 @@ "node": ">=4.0.0" } }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "node_modules/compare-versions": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", - "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", - "dev": true - }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -9765,12 +7123,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/confbox": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", - "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", - "dev": true - }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", @@ -9780,21 +7132,6 @@ "node": ">=0.8" } }, - "node_modules/consola": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", - "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", - "dev": true, - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", - "dev": true - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -9848,7 +7185,6 @@ "version": "3.38.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.0.tgz", "integrity": "sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A==", - "dev": true, "dependencies": { "browserslist": "^4.23.3" }, @@ -9867,7 +7203,6 @@ "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", @@ -10000,80 +7335,6 @@ "node": ">= 8" } }, - "node_modules/crypto-random-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", - "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", - "dev": true, - "dependencies": { - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/crypto-random-string/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/css-loader": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", - "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", - "dev": true, - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.1.0", - "postcss-modules-local-by-default": "^4.0.5", - "postcss-modules-scope": "^3.2.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/css-loader/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/css-select": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", @@ -10094,7 +7355,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -10107,7 +7367,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, "engines": { "node": ">= 6" }, @@ -10121,29 +7380,15 @@ "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", "dev": true }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/cssfontparser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/cssfontparser/-/cssfontparser-1.2.1.tgz", - "integrity": "sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg==", - "dev": true + "integrity": "sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg==" }, "node_modules/csso": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, "dependencies": { "css-tree": "~2.2.0" }, @@ -10156,7 +7401,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -10169,8 +7413,7 @@ "node_modules/csso/node_modules/mdn-data": { "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" }, "node_modules/cssom": { "version": "0.5.0", @@ -10590,18 +7833,6 @@ } } }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/deep-equal": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", @@ -10644,7 +7875,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -10689,18 +7919,6 @@ "node": ">= 10" } }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -10747,12 +7965,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "dev": true - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -10790,15 +8002,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -10910,7 +8113,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, "funding": [ { "type": "github", @@ -10973,7 +8175,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -11064,8 +8265,7 @@ "node_modules/electron-to-chromium": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", - "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==", - "dev": true + "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==" }, "node_modules/emittery": { "version": "0.13.1", @@ -11112,23 +8312,6 @@ "once": "^1.4.0" } }, - "node_modules/endent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/endent/-/endent-2.1.0.tgz", - "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==", - "dev": true, - "dependencies": { - "dedent": "^0.7.0", - "fast-json-parse": "^1.0.3", - "objectorarray": "^1.0.5" - } - }, - "node_modules/endent/node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, "node_modules/enhanced-resolve": { "version": "5.17.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", @@ -11159,7 +8342,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, "engines": { "node": ">=0.12" }, @@ -11365,67 +8547,16 @@ "is-symbol": "^1.0.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "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" - } - }, - "node_modules/esbuild-register": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", - "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" + "node": ">= 0.4" }, - "peerDependencies": { - "esbuild": ">=0.12 <1" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/escalade": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, "engines": { "node": ">=6" } @@ -12034,20 +9165,10 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -12289,12 +9410,6 @@ "node": ">= 6" } }, - "node_modules/fast-json-parse": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", - "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", - "dev": true - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -12352,15 +9467,6 @@ "bser": "2.1.1" } }, - "node_modules/fd-package-json": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-1.2.0.tgz", - "integrity": "sha512-45LSPmWf+gC5tdCQMNH4s9Sr00bIkiD9aN7dc5hqkrEw1geRYyDQS1v1oMHAW3ysfxfndqGsrDREHHjNNbKUfA==", - "dev": true, - "dependencies": { - "walk-up-path": "^3.0.1" - } - }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -12406,26 +9512,6 @@ "node": ">=16.0.0" } }, - "node_modules/file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -12447,15 +9533,6 @@ "node": ">=10" } }, - "node_modules/filesize": { - "version": "10.1.6", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz", - "integrity": "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==", - "dev": true, - "engines": { - "node": ">= 10.4.0" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -12501,38 +9578,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-cache-dir/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -12582,15 +9627,6 @@ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, - "node_modules/flow-parser": { - "version": "0.245.2", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.245.2.tgz", - "integrity": "sha512-FU4yuqC1j2IeWWicpzG0YJrXHJgKjK/AU8QKK/7MvQaNhcoGisDoE7FJLGCtbvnifzsgDWdm9/jtTF7Mp+PJXQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/follow-redirects": { "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", @@ -12835,36 +9871,6 @@ "node": ">=12" } }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/fs-monkey": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", @@ -12930,7 +9936,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -12944,15 +9949,6 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -13040,31 +10036,6 @@ "assert-plus": "^1.0.0" } }, - "node_modules/giget": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.3.tgz", - "integrity": "sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==", - "dev": true, - "dependencies": { - "citty": "^0.1.6", - "consola": "^3.2.3", - "defu": "^6.1.4", - "node-fetch-native": "^1.6.3", - "nypm": "^0.3.8", - "ohash": "^1.1.3", - "pathe": "^1.1.2", - "tar": "^6.2.0" - }, - "bin": { - "giget": "dist/cli.mjs" - } - }, - "node_modules/github-slugger": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", - "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", - "dev": true - }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -13199,6 +10170,24 @@ "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } }, + "node_modules/haengdong-design": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.81.tgz", + "integrity": "sha512-IiXkt0zXSEmn7vstTLOeNZLFS35JO8lXbXavM55wdyAJd+w0e5kfRxyDk/K2oSiAnX2c2YPiGep/A0x2/gZPDg==", + "dependencies": { + "@emotion/react": "^11.11.4", + "@storybook/addon-webpack5-compiler-swc": "^1.0.5", + "@svgr/webpack": "^8.1.0", + "lottie-react": "^2.4.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "engines": { + "node": ">=20.15.1", + "npm": ">=10.7.0" + } + }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -13284,45 +10273,6 @@ "node": ">= 0.4" } }, - "node_modules/hast-util-heading-rank": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", - "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", - "dev": true, - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-is-element": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", - "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", - "dev": true, - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.0.tgz", - "integrity": "sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==", - "dev": true, - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -13469,18 +10419,6 @@ "node": "^14.13.1 || >=16.0.0" } }, - "node_modules/html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/html-webpack-plugin": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", @@ -13719,18 +10657,6 @@ "node": ">=0.10.0" } }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -13870,18 +10796,6 @@ "node": ">= 10" } }, - "node_modules/is-absolute-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", - "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -14157,15 +11071,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -14747,7 +11652,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jest-canvas-mock/-/jest-canvas-mock-2.5.2.tgz", "integrity": "sha512-vgnpPupjOL6+L5oJXzxTxFrlGEIbHdZqFU+LFNdtLxZ3lRDCl17FlTMM7IatoRQkrcyOTMlDinjUguqmQ6bR2A==", - "dev": true, "dependencies": { "cssfontparser": "^1.2.1", "moo-color": "^1.0.2" @@ -16384,12 +13288,6 @@ "node": ">=8" } }, - "node_modules/jest-transform-stub": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jest-transform-stub/-/jest-transform-stub-2.0.0.tgz", - "integrity": "sha512-lspHaCRx/mBbnm3h4uMMS3R5aZzMwyNpNIJLXj4cEsV0mIUtS4IjYJLSoyjRCtnxb6RIGJ4NL2quZzfIeNhbkg==", - "dev": true - }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", @@ -16700,139 +13598,18 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "node_modules/jscodeshift": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.15.2.tgz", - "integrity": "sha512-FquR7Okgmc4Sd0aEDwqho3rEiKR3BdvuG9jfdHjLJ6JQoWSMpavug3AoIfnfWhxFlf+5pzQh8qjqz0DWFrNQzA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.23.0", - "@babel/parser": "^7.23.0", - "@babel/plugin-transform-class-properties": "^7.22.5", - "@babel/plugin-transform-modules-commonjs": "^7.23.0", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", - "@babel/plugin-transform-optional-chaining": "^7.23.0", - "@babel/plugin-transform-private-methods": "^7.22.5", - "@babel/preset-flow": "^7.22.15", - "@babel/preset-typescript": "^7.23.0", - "@babel/register": "^7.22.15", - "babel-core": "^7.0.0-bridge.0", - "chalk": "^4.1.2", - "flow-parser": "0.*", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.4", - "neo-async": "^2.5.0", - "node-dir": "^0.1.17", - "recast": "^0.23.3", - "temp": "^0.8.4", - "write-file-atomic": "^2.3.0" - }, - "bin": { - "jscodeshift": "bin/jscodeshift.js" - }, - "peerDependencies": { - "@babel/preset-env": "^7.1.6" - }, - "peerDependenciesMeta": { - "@babel/preset-env": { - "optional": true - } - } - }, - "node_modules/jscodeshift/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jscodeshift/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jscodeshift/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jscodeshift/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jscodeshift/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jscodeshift/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "argparse": "^2.0.1" }, - "engines": { - "node": ">=8" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jscodeshift/node_modules/write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true }, "node_modules/jsdom": { "version": "24.1.1", @@ -16997,7 +13774,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -17244,20 +14020,6 @@ "node": ">=6.11.5" } }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, "node_modules/loader-utils-webpack-v4": { "name": "loader-utils", "version": "2.0.4", @@ -17297,8 +14059,7 @@ "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "node_modules/lodash.memoize": { "version": "4.1.2", @@ -17534,20 +14295,10 @@ "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==" }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, "node_modules/lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, "dependencies": { "tslib": "^2.0.3" } @@ -17556,7 +14307,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "dependencies": { "yallist": "^3.0.2" } @@ -17624,29 +14374,10 @@ "tmpl": "1.0.5" } }, - "node_modules/map-or-similar": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", - "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", - "dev": true - }, - "node_modules/markdown-to-jsx": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.5.0.tgz", - "integrity": "sha512-RrBNcMHiFPcz/iqIj0n3wclzHXjwS7mzjBNWecKKVhNTIxQepIix6Il/wZCn2Cg5Y1ow2Qi84+eJrryFRWBEWw==", - "dev": true, - "engines": { - "node": ">= 10" - }, - "peerDependencies": { - "react": ">= 0.14.0" - } - }, "node_modules/mdn-data": { "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" }, "node_modules/media-typer": { "version": "0.3.0", @@ -17669,15 +14400,6 @@ "node": ">= 4.0.0" } }, - "node_modules/memoizerific": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", - "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", - "dev": true, - "dependencies": { - "map-or-similar": "^1.5.0" - } - }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -17811,61 +14533,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mlly": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", - "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", - "dev": true, - "dependencies": { - "acorn": "^8.11.3", - "pathe": "^1.1.2", - "pkg-types": "^1.1.1", - "ufo": "^1.5.3" - } - }, "node_modules/modify-source-webpack-plugin": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/modify-source-webpack-plugin/-/modify-source-webpack-plugin-4.1.0.tgz", @@ -17936,7 +14603,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/moo-color/-/moo-color-1.0.3.tgz", "integrity": "sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ==", - "dev": true, "dependencies": { "color-name": "^1.1.4" } @@ -17944,8 +14610,7 @@ "node_modules/moo-color/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/ms": { "version": "2.1.2", @@ -18093,24 +14758,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -18136,7 +14783,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -18148,40 +14794,6 @@ "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", "dev": true }, - "node_modules/node-dir": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", - "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", - "dev": true, - "dependencies": { - "minimatch": "^3.0.2" - }, - "engines": { - "node": ">= 0.10.5" - } - }, - "node_modules/node-dir/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/node-dir/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -18202,12 +14814,6 @@ } } }, - "node_modules/node-fetch-native": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.4.tgz", - "integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==", - "dev": true - }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -18226,202 +14832,46 @@ "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/nwsapi": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", - "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", - "dev": true - }, - "node_modules/nypm": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.11.tgz", - "integrity": "sha512-E5GqaAYSnbb6n1qZyik2wjPDZON43FqOJO59+3OkWrnmQtjggrMOVnsyzfjxp/tS6nlYJBA4zRA5jSM2YaadMg==", - "dev": true, - "dependencies": { - "citty": "^0.1.6", - "consola": "^3.2.3", - "execa": "^8.0.1", - "pathe": "^1.1.2", - "pkg-types": "^1.2.0", - "ufo": "^1.5.4" - }, - "bin": { - "nypm": "dist/cli.mjs" - }, - "engines": { - "node": "^14.16.0 || >=16.10.0" - } - }, - "node_modules/nypm/node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/nypm/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/nypm/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/nypm/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, "engines": { - "node": ">=12" + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/nwsapi": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", + "dev": true + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -18548,24 +14998,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/objectorarray": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz", - "integrity": "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==", - "dev": true - }, "node_modules/obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "dev": true }, - "node_modules/ohash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.3.tgz", - "integrity": "sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==", - "dev": true - }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -18646,99 +15084,6 @@ "node": ">= 0.8.0" } }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ora/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/ora/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ospath": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", @@ -18897,12 +15242,6 @@ "tslib": "^2.0.3" } }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -18971,21 +15310,6 @@ "node": ">=8" } }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -19097,29 +15421,6 @@ "node": ">=8" } }, - "node_modules/pkg-types": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.0.tgz", - "integrity": "sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==", - "dev": true, - "dependencies": { - "confbox": "^0.1.7", - "mlly": "^1.7.1", - "pathe": "^1.1.2" - } - }, - "node_modules/polished": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", - "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.17.8" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -19129,112 +15430,6 @@ "node": ">= 0.4" } }, - "node_modules/postcss": { - "version": "8.4.45", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz", - "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -19509,124 +15704,42 @@ "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-colorful": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", - "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", - "dev": true, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/react-confetti": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz", - "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==", - "dev": true, - "dependencies": { - "tween-functions": "^1.2.0" - }, - "engines": { - "node": ">=10.18" - }, - "peerDependencies": { - "react": "^16.3.0 || ^17.0.1 || ^18.0.0" - } - }, - "node_modules/react-copy-to-clipboard": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", - "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==", - "dependencies": { - "copy-to-clipboard": "^3.3.1", - "prop-types": "^15.8.1" - }, - "peerDependencies": { - "react": "^15.3.0 || 16 || 17 || 18" - } - }, - "node_modules/react-docgen": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-7.0.3.tgz", - "integrity": "sha512-i8aF1nyKInZnANZ4uZrH49qn1paRgBZ7wZiCNBMnenlPzEv0mRl+ShpTVEI6wZNl8sSc79xZkivtgLKQArcanQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.18.9", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9", - "@types/babel__core": "^7.18.0", - "@types/babel__traverse": "^7.18.0", - "@types/doctrine": "^0.0.9", - "@types/resolve": "^1.20.2", - "doctrine": "^3.0.0", - "resolve": "^1.22.1", - "strip-indent": "^4.0.0" + "unpipe": "1.0.0" }, "engines": { - "node": ">=16.14.0" + "node": ">= 0.8" } }, - "node_modules/react-docgen-typescript": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz", - "integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==", + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, - "peerDependencies": { - "typescript": ">= 4.3.x" + "engines": { + "node": ">= 0.8" } }, - "node_modules/react-docgen/node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { - "esutils": "^2.0.2" + "loose-envify": "^1.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, - "node_modules/react-docgen/node_modules/strip-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", - "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", - "dev": true, + "node_modules/react-copy-to-clipboard": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", + "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==", "dependencies": { - "min-indent": "^1.0.1" - }, - "engines": { - "node": ">=12" + "copy-to-clipboard": "^3.3.1", + "prop-types": "^15.8.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "react": "^15.3.0 || 16 || 17 || 18" } }, "node_modules/react-dom": { @@ -19641,36 +15754,6 @@ "react": "^18.3.1" } }, - "node_modules/react-element-to-jsx-string": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", - "integrity": "sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==", - "dev": true, - "dependencies": { - "@base2/pretty-print-object": "1.0.1", - "is-plain-object": "5.0.0", - "react-is": "18.1.0" - }, - "peerDependencies": { - "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", - "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0" - } - }, - "node_modules/react-element-to-jsx-string/node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-element-to-jsx-string/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, "node_modules/react-error-boundary": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz", @@ -19682,15 +15765,6 @@ "react": ">=16.13.1" } }, - "node_modules/react-inspector": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.2.tgz", - "integrity": "sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==", - "dev": true, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -19752,31 +15826,6 @@ "node": ">=8.10.0" } }, - "node_modules/recast": { - "version": "0.23.9", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.9.tgz", - "integrity": "sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==", - "dev": true, - "dependencies": { - "ast-types": "^0.16.1", - "esprima": "~4.0.0", - "source-map": "~0.6.1", - "tiny-invariant": "^1.3.3", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/recast/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -19826,14 +15875,12 @@ "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "node_modules/regenerate-unicode-properties": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", - "dev": true, "dependencies": { "regenerate": "^1.4.2" }, @@ -19850,7 +15897,6 @@ "version": "0.15.2", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dev": true, "dependencies": { "@babel/runtime": "^7.8.4" } @@ -19877,7 +15923,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "dev": true, "dependencies": { "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", @@ -19894,7 +15939,6 @@ "version": "0.9.1", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dev": true, "dependencies": { "jsesc": "~0.5.0" }, @@ -19906,46 +15950,10 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" } }, - "node_modules/rehype-external-links": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", - "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", - "dev": true, - "dependencies": { - "@types/hast": "^3.0.0", - "@ungap/structured-clone": "^1.0.0", - "hast-util-is-element": "^3.0.0", - "is-absolute-url": "^4.0.0", - "space-separated-tokens": "^2.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/rehype-slug": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", - "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", - "dev": true, - "dependencies": { - "@types/hast": "^3.0.0", - "github-slugger": "^2.0.0", - "hast-util-heading-rank": "^3.0.0", - "hast-util-to-string": "^3.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", @@ -20289,7 +16297,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -20611,7 +16618,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", - "dev": true, "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -20640,7 +16646,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -20664,16 +16669,6 @@ "node": ">=0.10.0" } }, - "node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -20759,247 +16754,22 @@ "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/storybook": { - "version": "8.2.9", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.2.9.tgz", - "integrity": "sha512-S7Q/Yt4A+nu1O23rg39lQvBqL2Vg+PKXbserDWUR4LFJtfmoZ2xGO8oFIhJmvvhjUBvolw1q7QDeswPq2i0sGw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.24.4", - "@babel/types": "^7.24.0", - "@storybook/codemod": "8.2.9", - "@storybook/core": "8.2.9", - "@types/semver": "^7.3.4", - "@yarnpkg/fslib": "2.10.3", - "@yarnpkg/libzip": "2.3.0", - "chalk": "^4.1.0", - "commander": "^6.2.1", - "cross-spawn": "^7.0.3", - "detect-indent": "^6.1.0", - "envinfo": "^7.7.3", - "execa": "^5.0.0", - "fd-package-json": "^1.2.0", - "find-up": "^5.0.0", - "fs-extra": "^11.1.0", - "giget": "^1.0.0", - "globby": "^14.0.1", - "jscodeshift": "^0.15.1", - "leven": "^3.1.0", - "ora": "^5.4.1", - "prettier": "^3.1.1", - "prompts": "^2.4.0", - "semver": "^7.3.7", - "strip-json-comments": "^3.0.1", - "tempy": "^3.1.0", - "tiny-invariant": "^1.3.1", - "ts-dedent": "^2.0.0" - }, - "bin": { - "getstorybook": "bin/index.cjs", - "sb": "bin/index.cjs", - "storybook": "bin/index.cjs" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - } - }, - "node_modules/storybook-addon-react-router-v6": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/storybook-addon-react-router-v6/-/storybook-addon-react-router-v6-2.0.15.tgz", - "integrity": "sha512-4vOYIQwehlQLyXaCT9K0Iu0po2Z+pANGsqkfm/BQuAEjE9MoN7vrsrQLHINhKbmQVtNMmuS/oBR3GGNbqQ1gew==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "compare-versions": "^6.0.0", - "react-inspector": "6.0.2" - }, - "peerDependencies": { - "@storybook/blocks": "^7.0.0", - "@storybook/channels": "^7.0.0", - "@storybook/components": "^7.0.0", - "@storybook/core-events": "^7.0.0", - "@storybook/manager-api": "^7.0.0", - "@storybook/preview-api": "^7.0.0", - "@storybook/theming": "^7.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-router-dom": "^6.4.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/storybook/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/storybook/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/storybook/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/storybook/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/storybook/node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/storybook/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/storybook/node_modules/globby": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", - "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", - "dev": true, - "dependencies": { - "@sindresorhus/merge-streams": "^2.1.0", - "fast-glob": "^3.3.2", - "ignore": "^5.2.4", - "path-type": "^5.0.0", - "slash": "^5.1.0", - "unicorn-magic": "^0.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/storybook/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/storybook/node_modules/path-type": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", - "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/storybook/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/storybook/node_modules/slash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" } }, - "node_modules/storybook/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "internal-slot": "^1.0.4" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, "node_modules/strict-event-emitter": { @@ -21257,22 +17027,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/style-loader": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", - "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", @@ -21303,14 +17057,12 @@ "node_modules/svg-parser": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", - "dev": true + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" }, "node_modules/svgo": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", - "dev": true, "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -21335,7 +17087,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, "engines": { "node": ">= 10" } @@ -21344,7 +17095,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -21360,7 +17110,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -21374,7 +17123,6 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, "dependencies": { "domelementtype": "^2.3.0" }, @@ -21389,7 +17137,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -21403,7 +17150,6 @@ "version": "0.2.6", "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz", "integrity": "sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==", - "dev": true, "dependencies": { "@swc/counter": "^0.1.3" }, @@ -21443,166 +17189,6 @@ "node": ">=6" } }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/telejson": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/telejson/-/telejson-7.2.0.tgz", - "integrity": "sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==", - "dev": true, - "dependencies": { - "memoizerific": "^1.11.3" - } - }, - "node_modules/temp": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", - "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", - "dev": true, - "dependencies": { - "rimraf": "~2.6.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/temp-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", - "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", - "dev": true, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/temp/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/temp/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/temp/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/temp/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/tempy": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz", - "integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==", - "dev": true, - "dependencies": { - "is-stream": "^3.0.0", - "temp-dir": "^3.0.0", - "type-fest": "^2.12.2", - "unique-string": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/terser": { "version": "5.31.3", "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz", @@ -21757,21 +17343,6 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, - "node_modules/tiny-invariant": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", - "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", - "dev": true - }, - "node_modules/tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", @@ -21879,15 +17450,6 @@ "typescript": ">=4.2.0" } }, - "node_modules/ts-dedent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", - "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", - "dev": true, - "engines": { - "node": ">=6.10" - } - }, "node_modules/ts-jest": { "version": "29.2.4", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.4.tgz", @@ -22129,8 +17691,7 @@ "node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/tunnel-agent": { "version": "0.6.0", @@ -22144,12 +17705,6 @@ "node": "*" } }, - "node_modules/tween-functions": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", - "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==", - "dev": true - }, "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", @@ -22314,12 +17869,6 @@ } } }, - "node_modules/ufo": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", - "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", - "dev": true - }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -22357,7 +17906,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, "engines": { "node": ">=4" } @@ -22366,7 +17914,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -22379,7 +17926,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", - "dev": true, "engines": { "node": ">=4" } @@ -22388,80 +17934,10 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "dev": true, "engines": { "node": ">=4" } }, - "node_modules/unicorn-magic": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", - "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/unique-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", - "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", - "dev": true, - "dependencies": { - "crypto-random-string": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -22505,7 +17981,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -22540,19 +18015,6 @@ "punycode": "^2.1.0" } }, - "node_modules/url": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", - "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", - "dev": true, - "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.12.3" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -22563,27 +18025,6 @@ "requires-port": "^1.0.0" } }, - "node_modules/url/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "dev": true - }, - "node_modules/url/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/use-sync-external-store": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", @@ -22592,19 +18033,6 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -22702,12 +18130,6 @@ "node": ">=18" } }, - "node_modules/walk-up-path": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", - "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", - "dev": true - }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -22739,15 +18161,6 @@ "minimalistic-assert": "^1.0.0" } }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "dependencies": { - "defaults": "^1.0.3" - } - }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -23073,17 +18486,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/webpack-hot-middleware": { - "version": "2.26.1", - "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.26.1.tgz", - "integrity": "sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==", - "dev": true, - "dependencies": { - "ansi-html-community": "0.0.8", - "html-entities": "^2.1.0", - "strip-ansi": "^6.0.0" - } - }, "node_modules/webpack-merge": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", @@ -23504,8 +18906,7 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { "version": "1.10.2", diff --git a/client/package.json b/client/package.json index 8c308b08b..6d673dd06 100644 --- a/client/package.json +++ b/client/package.json @@ -8,8 +8,6 @@ "dev": "NODE_ENV=development webpack server --open --config webpack.dev.mjs", "build": "NODE_ENV=production webpack --config webpack.prod.mjs", "build-dev": "NODE_ENV=development webpack --config webpack.dev.mjs", - "build-storybook": "storybook build", - "storybook": "storybook dev -p 6006", "lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'", "cypress-open": "cypress open", @@ -20,20 +18,10 @@ "author": "", "license": "ISC", "devDependencies": { - "@chromatic-com/storybook": "^1.6.1", "@eslint/compat": "^1.1.0", "@eslint/js": "^9.6.0", "@jest/types": "^29.6.3", "@sentry/webpack-plugin": "^2.22.0", - "@storybook/addon-essentials": "^8.2.2", - "@storybook/addon-interactions": "^8.2.2", - "@storybook/addon-links": "^8.2.2", - "@storybook/addon-onboarding": "^8.2.2", - "@storybook/addon-webpack5-compiler-swc": "^1.0.5", - "@storybook/blocks": "^8.2.2", - "@storybook/react": "^8.2.2", - "@storybook/react-webpack5": "^8.2.3", - "@storybook/test": "^8.2.2", "@svgr/webpack": "^8.1.0", "@tanstack/react-query-devtools": "^5.52.0", "@testing-library/dom": "^10.4.0", @@ -56,21 +44,16 @@ "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-react": "^7.34.3", "eslint-plugin-react-hooks": "^4.6.2", - "file-loader": "^6.2.0", "fork-ts-checker-webpack-plugin": "^9.0.2", "globals": "^15.8.0", "html-loader": "^5.0.0", "html-webpack-plugin": "^5.6.0", "jest": "^29.7.0", - "jest-canvas-mock": "^2.5.2", "jest-environment-jsdom": "^29.7.0", - "jest-transform-stub": "^2.0.0", "jsdom": "^24.1.1", "modify-source-webpack-plugin": "^4.1.0", "msw": "^2.3.5", "prettier": "3.3.2", - "storybook": "^8.2.2", - "storybook-addon-react-router-v6": "^2.0.15", "ts-jest": "^29.2.4", "ts-loader": "^9.5.1", "ts-node": "^10.9.2", @@ -86,7 +69,8 @@ "@emotion/react": "^11.11.4", "@sentry/react": "^8.25.0", "@tanstack/react-query": "^5.51.23", - "lottie-react": "^2.4.0", + "haengdong-design": "^0.1.81", + "jest-canvas-mock": "^2.5.2", "react": "^18.3.1", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", diff --git a/client/src/App.tsx b/client/src/App.tsx index 33ea71b6c..4e9ce39e1 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,35 +1,29 @@ import {Outlet} from 'react-router-dom'; +import {HDesignProvider} from 'haengdong-design'; import {Global} from '@emotion/react'; import {ReactQueryDevtools} from '@tanstack/react-query-devtools'; +import {ToastProvider} from '@hooks/useToast/ToastProvider'; import QueryClientBoundary from '@components/QueryClientBoundary/QueryClientBoundary'; import ErrorCatcher from '@components/AppErrorBoundary/ErrorCatcher'; -import ToastContainer from '@components/Toast/ToastContainer'; -import KakaoInitializer from '@components/KakaoInitializer/KakaoInitializer'; - -import {HDesignProvider} from '@HDesign/index'; - -import NetworkStateCatcher from '@utils/NetworkStateCatcher'; import {GlobalStyle} from './GlobalStyle'; -import UnPredictableErrorBoundary from './UnPredictableErrorBoundary'; +import UnhandledErrorBoundary from './UnhandledErrorBoundary'; const App: React.FC = () => { return ( - + - - - - - - + + + + - - - - + + + + ); }; diff --git a/client/src/GlobalStyle.ts b/client/src/GlobalStyle.ts index b25bb94d1..ab16de8e1 100644 --- a/client/src/GlobalStyle.ts +++ b/client/src/GlobalStyle.ts @@ -2,147 +2,159 @@ import {css} from '@emotion/react'; // reset css -> index css export const GlobalStyle = css` - @import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css'); - - *:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) { - all: unset; - display: revert; - } - - /* Preferred box-sizing value */ - *, - *::before, - *::after { - box-sizing: border-box; - } - - /* Fix mobile Safari increase font-size on landscape mode */ - html { - -moz-text-size-adjust: none; - -webkit-text-size-adjust: none; - text-size-adjust: none; - } - - /* Reapply the pointer cursor for anchor tags */ + html, + body, + div, + span, + applet, + object, + iframe, + h1, + h2, + h3, + h4, + h5, + h6, + p, + blockquote, + pre, a, - button { - cursor: revert; - line-height: 0; - } - - button:disabled { - cursor: default; - } - - /* Remove list styles (bullets/numbers) */ + abbr, + acronym, + address, + big, + cite, + code, + del, + dfn, + em, + img, + ins, + kbd, + q, + s, + samp, + small, + strike, + strong, + sub, + sup, + tt, + b, + u, + i, + center, + dl, + dt, + dd, ol, ul, + li, + fieldset, + form, + label, + legend, + table, + caption, + tbody, + tfoot, + thead, + tr, + th, + td, + article, + aside, + canvas, + details, + embed, + figure, + figcaption, + footer, + header, + hgroup, menu, - summary { - list-style: none; - } - - /* Removes spacing between cells in tables */ - table { - border-collapse: collapse; - } - - /* Safari - solving issue when using user-select:none on the text input doesn't working */ - input, - textarea { - -webkit-user-select: auto; + nav, + output, + ruby, + section, + summary, + time, + mark, + audio, + video { + vertical-align: baseline; + margin: 0; + border: 0; + padding: 0; + font-size: 100%; + font: inherit; + } + /* HTML5 display-role reset for older browsers */ + article, + aside, + details, + figcaption, + figure, + footer, + header, + hgroup, + menu, + nav, + section { + display: block; } - - /* Revert the 'white-space' property for textarea elements on Safari */ - textarea { - white-space: revert; + body { + line-height: 1; } - - /* Minimum style to allow to style meter element */ - meter { - -webkit-appearance: revert; - appearance: revert; + ol, + ul { + list-style: none; } - - /* Preformatted text - use only for this feature */ - :where(pre) { - all: revert; - box-sizing: border-box; + blockquote, + q { + quotes: none; } - - /* Fix the feature of 'hidden' attribute. - display: revert; revert to element instead of attribute */ - :where([hidden]) { - display: none; + blockquote:before, + blockquote:after, + q:before, + q:after { + content: ''; + content: none; } - - /* Revert for bug in Chromium browsers - - Fix for the content editable attribute will work properly. - - webkit-user-select: auto; added for Safari in case of using user-select:none on wrapper element */ - :where([contenteditable]:not([contenteditable='false'])) { - -moz-user-modify: read-write; - -webkit-user-modify: read-write; - overflow-wrap: break-word; - -webkit-line-break: after-white-space; - -webkit-user-select: auto; + table { + border-collapse: collapse; + border-spacing: 0; } - - /* Apply back the draggable feature - exist only in Chromium and Safari */ - :where([draggable='true']) { - -webkit-user-drag: element; + button { + cursor: pointer; + border: none; + background-color: transparent; } - - /* Revert Modal native behavior */ - :where(dialog:modal) { - all: revert; + * { box-sizing: border-box; } - /* Remove details summary webkit styles */ - ::-webkit-details-marker { - display: none; + html { + height: 100%; } - /* Chrome, Safari, Edge, Opera */ - input::-webkit-outer-spin-button, - input::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; + body { + max-width: 768px; + height: 100%; + margin: 0 auto; + + overflow-y: scroll; + &::-webkit-scrollbar { + display: none; + } } - /* Firefox */ - input[type='number'] { - -moz-appearance: textfield; + section { + width: 100%; } #root { display: flex; - justify-content: center; - } - - button { - cursor: pointer; - } - - body { - font-family: - 'Pretendard', - -apple-system, - BlinkMacSystemFont, - system-ui, - Roboto, - 'Helvetica Neue', - 'Segoe UI', - 'Apple SD Gothic Neo', - 'Noto Sans KR', - 'Malgun Gothic', - 'Apple Color Emoji', - 'Segoe UI Emoji', - 'Segoe UI Symbol', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - max-width: 768px; - margin: 0 auto; + flex-direction: column; } `; diff --git a/client/src/UnPredictableErrorBoundary.tsx b/client/src/UnPredictableErrorBoundary.tsx deleted file mode 100644 index 7dce07a58..000000000 --- a/client/src/UnPredictableErrorBoundary.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import {ErrorBoundary} from 'react-error-boundary'; - -import {StrictPropsWithChildren} from '@type/strictPropsWithChildren'; -import ErrorPage from '@pages/ErrorPage/ErrorPage'; - -const UnPredictableErrorBoundary = ({children}: StrictPropsWithChildren) => { - return }>{children}; -}; - -export default UnPredictableErrorBoundary; diff --git a/client/src/UnhandledErrorBoundary.tsx b/client/src/UnhandledErrorBoundary.tsx new file mode 100644 index 000000000..78d017344 --- /dev/null +++ b/client/src/UnhandledErrorBoundary.tsx @@ -0,0 +1,10 @@ +import {StrictPropsWithChildren} from 'haengdong-design/dist/type/strictPropsWithChildren'; +import {ErrorBoundary} from 'react-error-boundary'; + +import ErrorPage from '@pages/ErrorPage/ErrorPage'; + +const UnhandledErrorBoundary = ({children}: StrictPropsWithChildren) => { + return }>{children}; +}; + +export default UnhandledErrorBoundary; diff --git a/client/src/apis/fetcher.ts b/client/src/apis/fetcher.ts index a1c205739..2e1c2d067 100644 --- a/client/src/apis/fetcher.ts +++ b/client/src/apis/fetcher.ts @@ -1,165 +1,120 @@ -import {RequestGetError, WithErrorHandlingStrategy} from '@errors/RequestGetError'; +import {ErrorInfo} from '@components/AppErrorBoundary/ErrorCatcher'; import objectToQueryString from '@utils/objectToQueryString'; -import RequestError from '../errors/RequestError'; +import {UNKNOWN_ERROR} from '@constants/errorMessage'; -export type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; - -export type ObjectQueryParams = Record; - -type ErrorInfo = { - errorCode: string; - message: string; -}; +import FetchError from '../errors/FetchError'; -/** - * fetch์˜ 2๋ฒˆ์งธ ์ธ์ž๋กœ ๋“ค์–ด๊ฐ€๋Š” ๋ฐ์ดํ„ฐ์˜ ํƒ€์ž…์€ RequestInit์œผ๋กœ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. - * ๋‹ค๋งŒ ์ด RequestInit์˜ ํƒ€์ž…์ด method๊ฐ€ optional์ด๋ผ์„œ ์ด๋ฅผ ๋ฐ˜๋“œ์‹œ ๋ฐ›๋„๋กํ•˜๊ธฐ ์œ„ํ•ด RequestInitWithMethod๋ผ๋Š” ํƒ€์ž…์œผ๋กœ ํ™•์žฅํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. - */ -type RequestInitWithMethod = Omit & {method: Method}; +export type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; +type Body = ReadableStream | XMLHttpRequestBodyInit; type HeadersType = [string, string][] | Record | Headers; -export type Body = BodyInit | object | null; +export type ObjectQueryParams = Record; type RequestProps = { baseUrl?: string; endpoint: string; headers?: HeadersType; - body?: Body; + body?: Body | object | null; queryParams?: ObjectQueryParams; +}; + +type FetcherProps = RequestProps & { method: Method; }; -type RequestMethodProps = Omit; +type Options = { + method: Method; + headers: HeadersType; + body?: Body | null; +}; -type FetchType = { +type ErrorHandlerProps = { url: string; - requestInit: RequestInitWithMethod; + options: Options; + body: string; }; const API_BASE_URL = process.env.API_BASE_URL ?? ''; -export const requestGet = async ({ - headers = {}, - errorHandlingStrategy, - ...args -}: WithErrorHandlingStrategy): Promise => { - const response = await request({ +export const requestGet = async ({headers = {}, ...args}: RequestProps): Promise => { + const response = await fetcher({ ...args, method: 'GET', headers, - errorHandlingStrategy, }); const data: T = await response!.json(); return data; }; -export const requestPatch = ({headers = {}, ...args}: RequestMethodProps) => { - return request({method: 'PATCH', headers, ...args}); +export const requestPatch = ({headers = {}, ...args}: RequestProps) => { + return fetcher({method: 'PATCH', headers, ...args}); }; -export const requestPut = ({headers = {}, ...args}: RequestMethodProps) => { - return request({method: 'PUT', headers, ...args}); +export const requestPut = ({headers = {}, ...args}: RequestProps) => { + return fetcher({method: 'PUT', headers, ...args}); }; -export const requestPostWithoutResponse = async ({headers = {}, ...args}: RequestMethodProps) => { - await request({method: 'POST', headers, ...args}); +export const requestPostWithoutResponse = async ({headers = {}, ...args}: RequestProps) => { + await fetcher({method: 'POST', headers, ...args}); }; -export const requestPostWithResponse = async ({headers = {}, ...args}: RequestMethodProps): Promise => { - const response = await request({method: 'POST', headers, ...args}); +export const requestPostWithResponse = async ({headers = {}, ...args}: RequestProps): Promise => { + const response = await fetcher({method: 'POST', headers, ...args}); const data: T = await response!.json(); return data; }; -export const requestDelete = ({headers = {}, ...args}: RequestMethodProps) => { - return request({method: 'DELETE', headers, ...args}); +export const requestDelete = ({headers = {}, ...args}: RequestProps) => { + return fetcher({method: 'DELETE', headers, ...args}); }; -const prepareRequest = ({baseUrl = API_BASE_URL, method, endpoint, headers, body, queryParams}: RequestProps) => { - let url = `${baseUrl}${endpoint}`; - - if (queryParams) url += `?${objectToQueryString(queryParams)}`; - - const requestInit: RequestInitWithMethod = { +const fetcher = ({baseUrl = API_BASE_URL, method, endpoint, headers, body, queryParams}: FetcherProps) => { + const options = { + method, credentials: 'include', headers: { 'Content-Type': 'application/json', ...headers, }, - method, body: body ? JSON.stringify(body) : null, }; - return {url, requestInit}; + let url = `${baseUrl}${endpoint}`; + + if (queryParams) url += `?${objectToQueryString(queryParams)}`; + + return errorHandler({url, options, body: JSON.stringify(body)}); }; -const executeRequest = async ({url, requestInit, errorHandlingStrategy}: WithErrorHandlingStrategy) => { +const errorHandler = async ({url, options, body}: ErrorHandlerProps) => { try { - const response: Response = await fetch(url, requestInit); + const response: Response = await fetch(url, options); if (!response.ok) { - throw await createError({ - response, - body: requestInit.body ? JSON.stringify(requestInit.body) : null, - requestInit, - errorHandlingStrategy, + const serverErrorInfo: ErrorInfo = await response.json(); + + throw new FetchError({ + status: response.status, + requestBody: body, + endpoint: response.url, + errorInfo: serverErrorInfo, + name: serverErrorInfo.errorCode, + message: serverErrorInfo.message || '', + method: options.method, }); } return response; } catch (error) { if (error instanceof Error) { - throw error; // ๊ทธ๋Œ€๋กœ RequestError ๋˜๋Š” Error ์ธ์Šคํ„ด์Šค๋ฅผ ๋˜์ง‘๋‹ˆ๋‹ค. + throw error; // ๊ทธ๋Œ€๋กœ FetchError || Error ์ธ์Šคํ„ด์Šค๋ฅผ ๋˜์ง‘๋‹ˆ๋‹ค. } - throw error; + throw new Error(UNKNOWN_ERROR); } }; - -const request = async (props: WithErrorHandlingStrategy) => { - const {url, requestInit} = prepareRequest(props); - return executeRequest({url, requestInit, errorHandlingStrategy: props.errorHandlingStrategy}); -}; - -type CreateError = { - response: Response; - body: Body; - requestInit: RequestInitWithMethod; -}; - -const createError = async ({ - response, - body, - requestInit, - errorHandlingStrategy, -}: WithErrorHandlingStrategy) => { - const {errorCode, message}: ErrorInfo = await response.json(); - - if (requestInit.method === 'GET') { - return new RequestGetError({ - status: response.status, - requestBody: body, - endpoint: response.url, - name: errorCode, - method: requestInit.method, - errorHandlingStrategy, - message, - errorCode, - }); - } - - return new RequestError({ - status: response.status, - requestBody: body, - endpoint: response.url, - name: errorCode, - method: requestInit.method, - message, - errorCode, - }); -}; diff --git a/client/src/apis/request/auth.ts b/client/src/apis/request/auth.ts index aac5c622d..9c56d1f6b 100644 --- a/client/src/apis/request/auth.ts +++ b/client/src/apis/request/auth.ts @@ -1,23 +1,23 @@ import {BASE_URL} from '@apis/baseUrl'; -import {ADMIN_API_PREFIX, USER_API_PREFIX} from '@apis/endpointPrefix'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; import {requestPostWithoutResponse} from '@apis/fetcher'; -import {WithEventId} from '@apis/withId.type'; +import {WithEventId} from '@apis/withEventId.type'; + +export type RequestToken = { + password: string; +}; export const requestPostAuthentication = async ({eventId}: WithEventId) => { await requestPostWithoutResponse({ baseUrl: BASE_URL.HD, - endpoint: `${ADMIN_API_PREFIX}/${eventId}/auth`, + endpoint: `${TEMP_PREFIX}/${eventId}/auth`, }); }; -export interface RequestPostToken { - password: string; -} - -export const requestPostToken = async ({eventId, password}: WithEventId) => { +export const requestPostToken = async ({eventId, password}: WithEventId) => { await requestPostWithoutResponse({ baseUrl: BASE_URL.HD, - endpoint: `${USER_API_PREFIX}/${eventId}/login`, + endpoint: `${TEMP_PREFIX}/${eventId}/login`, body: { password: password, }, diff --git a/client/src/apis/request/bill.ts b/client/src/apis/request/bill.ts index f78a7e6b8..c08168520 100644 --- a/client/src/apis/request/bill.ts +++ b/client/src/apis/request/bill.ts @@ -1,80 +1,69 @@ -import type {BillDetails} from 'types/serviceType'; - -import {WithErrorHandlingStrategy} from '@errors/RequestGetError'; +import type {Bill, MemberReportInAction} from 'types/serviceType'; import {BASE_URL} from '@apis/baseUrl'; -import {ADMIN_API_PREFIX, USER_API_PREFIX} from '@apis/endpointPrefix'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; import {requestDelete, requestGet, requestPostWithoutResponse, requestPut} from '@apis/fetcher'; -import {WithBillId, WithEventId} from '@apis/withId.type'; +import {WithEventId} from '@apis/withEventId.type'; -export interface RequestPostBill { - title: string; - price: number; - memberIds: number[]; -} +type RequestPostBillList = { + billList: Bill[]; +}; -export const requestPostBill = async ({eventId, title, price, memberIds}: WithEventId) => { +export const requestPostBillList = async ({eventId, billList}: WithEventId) => { await requestPostWithoutResponse({ baseUrl: BASE_URL.HD, - endpoint: `${ADMIN_API_PREFIX}/${eventId}/bills`, + endpoint: `${TEMP_PREFIX}/${eventId}/bill-actions`, body: { - title, - price, - memberIds, + actions: billList, }, }); }; -export const requestDeleteBill = async ({eventId, billId}: WithEventId) => { +type RequestBillAction = { + actionId: number; +}; + +export const requestDeleteBillAction = async ({eventId, actionId}: WithEventId) => { await requestDelete({ baseUrl: BASE_URL.HD, - endpoint: `${ADMIN_API_PREFIX}/${eventId}/bills/${billId}`, + endpoint: `${TEMP_PREFIX}/${eventId}/bill-actions/${actionId}`, }); }; -export interface RequestPutBill { - title: string; - price: number; -} +type RequestPutBillAction = Bill & RequestBillAction; -export const requestPutBill = async ({eventId, billId, title, price}: WithEventId>) => { +export const requestPutBillAction = async ({eventId, actionId, title, price}: WithEventId) => { await requestPut({ baseUrl: BASE_URL.HD, - endpoint: `${ADMIN_API_PREFIX}/${eventId}/bills/${billId}`, - body: {title, price}, + endpoint: `${TEMP_PREFIX}/${eventId}/bill-actions/${actionId}`, + body: { + title, + price, + }, }); }; -export const requestGetBillDetails = async ({ - eventId, - billId, - ...props -}: WithEventId>) => { - return requestGet({ +export type MemberReportList = {members: MemberReportInAction[]}; + +export const requestGetMemberReportListInAction = async ({eventId, actionId}: WithEventId) => { + return requestGet({ baseUrl: BASE_URL.HD, - endpoint: `${USER_API_PREFIX}/${eventId}/bills/${billId}/details`, - ...props, + endpoint: `${TEMP_PREFIX}/${eventId}/bill-actions/${actionId}/fixed`, }); }; -export interface PutBillDetail { - id: number; - price: number; - isFixed: boolean; -} +type RequestPutMemberReportList = RequestBillAction & MemberReportList; -export interface RequestPutBillDetails { - billDetails: PutBillDetail[]; -} - -export const requestPutBillDetails = async ({ +export const requestPutMemberReportListInAction = async ({ eventId, - billId, - billDetails, -}: WithEventId>) => { - await requestPut({ + actionId, + members, +}: WithEventId) => { + return requestPut({ baseUrl: BASE_URL.HD, - endpoint: `${ADMIN_API_PREFIX}/${eventId}/bills/${billId}/details`, - body: {billDetails}, + endpoint: `${TEMP_PREFIX}/${eventId}/bill-actions/${actionId}/fixed`, + body: { + members, + }, }); }; diff --git a/client/src/apis/request/event.ts b/client/src/apis/request/event.ts index 27104d0c8..c9299c813 100644 --- a/client/src/apis/request/event.ts +++ b/client/src/apis/request/event.ts @@ -1,41 +1,32 @@ -import {Event, EventId} from 'types/serviceType'; -import {WithErrorHandlingStrategy} from '@errors/RequestGetError'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestGet, requestPostWithResponse} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; -import {ADMIN_API_PREFIX, USER_API_PREFIX} from '@apis/endpointPrefix'; -import {requestGet, requestPatch, requestPostWithResponse, requestPut} from '@apis/fetcher'; -import {WithEventId} from '@apis/withId.type'; - -export interface RequestPostEvent { +export type RequestPostNewEvent = { eventName: string; - password: string; -} + password: number; +}; -export const requestPostEvent = async ({eventName, password}: RequestPostEvent) => { - return await requestPostWithResponse({ - endpoint: USER_API_PREFIX, - body: { - eventName, - password, - }, - }); +export type ResponsePostNewEvent = { + eventId: string; }; -export const requestGetEvent = async ({eventId, ...props}: WithEventId) => { - return await requestGet({ - endpoint: `${USER_API_PREFIX}/${eventId}`, - ...props, +export const requestPostNewEvent = async ({eventName, password}: RequestPostNewEvent) => { + return await requestPostWithResponse({ + endpoint: TEMP_PREFIX, + body: { + eventName: eventName, + password: password, + }, }); }; -export type RequestPatchEvent = WithEventId & { - eventOutline: Partial; +type ResponseGetEventName = { + eventName: string; }; -export const requestPatchEvent = async ({eventId, eventOutline}: RequestPatchEvent) => { - return requestPatch({ - endpoint: `${ADMIN_API_PREFIX}/${eventId}`, - body: { - ...eventOutline, - }, +export const requestGetEventName = async ({eventId}: WithEventId) => { + return requestGet({ + endpoint: `${TEMP_PREFIX}/${eventId}`, }); }; diff --git a/client/src/apis/request/member.ts b/client/src/apis/request/member.ts index 756412784..dd7152575 100644 --- a/client/src/apis/request/member.ts +++ b/client/src/apis/request/member.ts @@ -1,72 +1,84 @@ -import type {AllMembers, Members} from 'types/serviceType'; - -import {WithErrorHandlingStrategy} from '@errors/RequestGetError'; +import type {MemberType} from 'types/serviceType'; import {BASE_URL} from '@apis/baseUrl'; -import {ADMIN_API_PREFIX, USER_API_PREFIX} from '@apis/endpointPrefix'; -import {requestDelete, requestGet, requestPut, requestPostWithResponse} from '@apis/fetcher'; -import {WithEventId} from '@apis/withId.type'; - -export interface PostMember { - name: string; -} +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestDelete, requestGet, requestPut, requestPostWithoutResponse} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; -export interface RequestPostMembers { - members: PostMember[]; -} +type RequestPostMemberList = { + memberNameList: string[]; + type: MemberType; +}; -export const requestPostMembers = async ({eventId, members: newMembers}: WithEventId) => { - return await requestPostWithResponse({ +export const requestPostMemberList = async ({eventId, type, memberNameList}: WithEventId) => { + await requestPostWithoutResponse({ baseUrl: BASE_URL.HD, - endpoint: `${ADMIN_API_PREFIX}/${eventId}/members`, + endpoint: `${TEMP_PREFIX}/${eventId}/member-actions`, body: { - members: newMembers, + members: memberNameList, + status: type, }, }); }; -export interface RequestDeleteMember { - memberId: number; -} +type RequestDeleteMemberAction = { + actionId: number; +}; -export const requestDeleteMember = async ({eventId, memberId}: WithEventId) => { +export const requestDeleteMemberAction = async ({eventId, actionId}: WithEventId) => { await requestDelete({ baseUrl: BASE_URL.HD, - endpoint: `${ADMIN_API_PREFIX}/${eventId}/members/${memberId}`, + endpoint: `${TEMP_PREFIX}/${eventId}/member-actions/${actionId}`, }); }; -interface PutMember { - id: number; - name: string; - isDeposited: boolean; -} +type ResponseGetAllMemberList = { + memberNames: string[]; +}; -export interface RequestPutMembers { - members: PutMember[]; -} +export const requestGetAllMemberList = async ({eventId}: WithEventId) => { + return requestGet({ + endpoint: `${TEMP_PREFIX}/${eventId}/members`, + }); +}; + +export type MemberChange = { + before: string; + after: string; +}; -export const requestPutMembers = async ({eventId, members}: WithEventId) => { +type RequestPutAllMemberList = { + members: MemberChange[]; +}; + +export const requestPutAllMemberList = async ({eventId, members}: WithEventId) => { await requestPut({ baseUrl: BASE_URL.HD, - endpoint: `${ADMIN_API_PREFIX}/${eventId}/members`, + endpoint: `${TEMP_PREFIX}/${eventId}/members/nameChange`, body: { - members: members, + members, }, }); }; -export const requestGetCurrentMembers = async ({eventId, ...props}: WithEventId) => { - return await requestGet({ +type RequestDeleteAllMemberList = { + memberName: string; +}; + +export const requestDeleteAllMemberList = async ({eventId, memberName}: WithEventId) => { + await requestDelete({ baseUrl: BASE_URL.HD, - endpoint: `${USER_API_PREFIX}/${eventId}/members/current`, - ...props, + endpoint: `${TEMP_PREFIX}/${eventId}/members/${memberName}`, }); }; -export const requestGetAllMembers = async ({eventId, ...props}: WithEventId) => { - return await requestGet({ - endpoint: `${USER_API_PREFIX}/${eventId}/members`, - ...props, +export type ResponseGetCurrentInMemberList = { + memberNames: string[]; +}; + +export const requestGetCurrentInMemberList = async ({eventId}: WithEventId) => { + return await requestGet({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/members/current`, }); }; diff --git a/client/src/apis/request/report.ts b/client/src/apis/request/report.ts index 51fc418a8..8992f9c30 100644 --- a/client/src/apis/request/report.ts +++ b/client/src/apis/request/report.ts @@ -1,16 +1,19 @@ -import type {Reports} from 'types/serviceType'; - -import {WithErrorHandlingStrategy} from '@errors/RequestGetError'; +import type {MemberReport} from 'types/serviceType'; import {BASE_URL} from '@apis/baseUrl'; -import {USER_API_PREFIX} from '@apis/endpointPrefix'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; import {requestGet} from '@apis/fetcher'; -import {WithEventId} from '@apis/withId.type'; +import {WithEventId} from '@apis/withEventId.type'; + +type ResponseGetMemberReportList = { + reports: MemberReport[]; +}; -export const requestGetReports = async ({eventId, ...props}: WithEventId) => { - return await requestGet({ +export const requestGetMemberReportList = async ({eventId}: WithEventId) => { + const {reports} = await requestGet({ baseUrl: BASE_URL.HD, - endpoint: `${USER_API_PREFIX}/${eventId}/reports`, - ...props, + endpoint: `${TEMP_PREFIX}/${eventId}/actions/reports`, }); + + return reports; }; diff --git a/client/src/apis/request/step.ts b/client/src/apis/request/step.ts deleted file mode 100644 index e0f205e22..000000000 --- a/client/src/apis/request/step.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {Steps} from 'types/serviceType'; -import {WithErrorHandlingStrategy} from '@errors/RequestGetError'; - -import {BASE_URL} from '@apis/baseUrl'; -import {USER_API_PREFIX} from '@apis/endpointPrefix'; -import {requestGet} from '@apis/fetcher'; -import {WithEventId} from '@apis/withId.type'; - -export const requestGetSteps = async ({eventId, ...props}: WithEventId) => { - const {steps} = await requestGet({ - baseUrl: BASE_URL.HD, - endpoint: `${USER_API_PREFIX}/${eventId}/bills`, - ...props, - }); - - return steps; -}; diff --git a/client/src/apis/request/stepList.ts b/client/src/apis/request/stepList.ts new file mode 100644 index 000000000..0d47ab90e --- /dev/null +++ b/client/src/apis/request/stepList.ts @@ -0,0 +1,17 @@ +import type {StepList} from 'types/serviceType'; + +import {BASE_URL} from '@apis/baseUrl'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestGet} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; + +// TODO: (@weadie) ํ˜„์žฌ ํ† ํฐ์„ ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ• ์ง€.. ๊ณ„์† ์‚ฌ์šฉ๋˜๋Š”๋ฐ +export const requestGetStepList = async ({eventId}: WithEventId) => { + // TODO: (@weadie) response๊ฐ€ ์–ด๋–ป๊ฒŒ ์˜ค๋Š”์ง€ ์•ˆ๋‚˜์™€์„œ data๋กœ๋งŒ ์จ๋’€์–ด์š”. + const {steps} = await requestGet({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/actions`, + }); + + return steps; +}; diff --git a/client/src/apis/endpointPrefix.ts b/client/src/apis/tempPrefix.ts similarity index 63% rename from client/src/apis/endpointPrefix.ts rename to client/src/apis/tempPrefix.ts index 18b5756cf..949981b73 100644 --- a/client/src/apis/endpointPrefix.ts +++ b/client/src/apis/tempPrefix.ts @@ -1,3 +1,2 @@ // TODO: (@weadie) ๋ฐ˜๋ณต๋˜์„œ ์“ฐ์ด๋Š” ์ด api/events๊ฐ€ ์ถ”ํ›„ ์ˆ˜์ • ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์–ด์„œ ์ผ๋‹จ ํŽธ์ง‘ํ•˜๊ธฐ ํŽธํ•˜๊ฒŒ ์ด ๋ณ€์ˆ˜๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค. -export const USER_API_PREFIX = '/api/events'; -export const ADMIN_API_PREFIX = '/api/admin/events'; +export const TEMP_PREFIX = '/api/events'; diff --git a/client/src/apis/withId.type.ts b/client/src/apis/withEventId.type.ts similarity index 50% rename from client/src/apis/withId.type.ts rename to client/src/apis/withEventId.type.ts index 2b1d3c2e8..b88160e3e 100644 --- a/client/src/apis/withId.type.ts +++ b/client/src/apis/withEventId.type.ts @@ -1,7 +1,3 @@ export type WithEventId

= P & { eventId: string; }; - -export type WithBillId

= P & { - billId: number; -}; diff --git a/client/src/assets/image/Toss_Symbol_Primary.png b/client/src/assets/image/Toss_Symbol_Primary.png deleted file mode 100644 index c6105618f..000000000 Binary files a/client/src/assets/image/Toss_Symbol_Primary.png and /dev/null differ diff --git a/client/src/assets/image/banksprite.png b/client/src/assets/image/banksprite.png deleted file mode 100644 index 6c68af62a..000000000 Binary files a/client/src/assets/image/banksprite.png and /dev/null differ diff --git a/client/src/assets/image/check.svg b/client/src/assets/image/check.svg deleted file mode 100644 index 66ed75336..000000000 --- a/client/src/assets/image/check.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/client/src/assets/image/editPencil.svg b/client/src/assets/image/editPencil.svg deleted file mode 100644 index 382e8ffd6..000000000 --- a/client/src/assets/image/editPencil.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/client/src/assets/image/meatballs.svg b/client/src/assets/image/meatballs.svg deleted file mode 100644 index bc3e17d2f..000000000 --- a/client/src/assets/image/meatballs.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/client/src/assets/image/pencil_mini.svg b/client/src/assets/image/pencil_mini.svg deleted file mode 100644 index 11a154e13..000000000 --- a/client/src/assets/image/pencil_mini.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/client/src/assets/image/trash_mini.svg b/client/src/assets/image/trash_mini.svg deleted file mode 100644 index 16436f446..000000000 --- a/client/src/assets/image/trash_mini.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/client/src/assets/image/x.svg b/client/src/assets/image/x.svg deleted file mode 100644 index c3622bab5..000000000 --- a/client/src/assets/image/x.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/client/src/components/AmountInput/AmountInput.stories.tsx b/client/src/components/AmountInput/AmountInput.stories.tsx deleted file mode 100644 index 84cedb178..000000000 --- a/client/src/components/AmountInput/AmountInput.stories.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import AmountInput from './AmountInput'; - -const meta = { - title: 'Components/AmountInput', - component: AmountInput, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: {}, - args: { - value: '112,000', - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = {}; diff --git a/client/src/components/AmountInput/AmountInput.tsx b/client/src/components/AmountInput/AmountInput.tsx deleted file mode 100644 index 1169e6c4b..000000000 --- a/client/src/components/AmountInput/AmountInput.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {css} from '@emotion/react'; - -import {Text, useTheme} from '@components/Design'; - -interface Props { - value: string; - onClick?: () => void; - underlined?: boolean; - activated?: boolean; -} - -const AmountInput = ({value, onClick, underlined, activated}: Props) => { - const {theme} = useTheme(); - return ( -

- - {value === '' ? '0' : value} - - - ์› - -
- ); -}; - -export default AmountInput; diff --git a/client/src/components/AppErrorBoundary/ErrorCatcher.test.tsx b/client/src/components/AppErrorBoundary/ErrorCatcher.test.tsx index f263e18fb..8d7946b8a 100644 --- a/client/src/components/AppErrorBoundary/ErrorCatcher.test.tsx +++ b/client/src/components/AppErrorBoundary/ErrorCatcher.test.tsx @@ -1,17 +1,16 @@ import {render, screen, waitFor} from '@testing-library/react'; import {act, ReactNode} from 'react'; import {MemoryRouter} from 'react-router-dom'; +import {HDesignProvider} from 'haengdong-design'; -import ToastContainer from '@components/Toast/ToastContainer'; -import RequestError from '@errors/RequestError'; +import FetchError from '@errors/FetchError'; +import {ToastProvider} from '@hooks/useToast/ToastProvider'; import {useAppErrorStore} from '@store/appErrorStore'; -import {HDesignProvider} from '@HDesign/index'; - import {SERVER_ERROR_MESSAGES} from '@constants/errorMessage'; -import UnPredictableErrorBoundary from '../../UnPredictableErrorBoundary'; +import UnhandledErrorBoundary from '../../UnhandledErrorBoundary'; import ErrorCatcher from './ErrorCatcher'; @@ -23,12 +22,13 @@ const TestComponent = ({triggerError}: {triggerError: () => void}) => { const setup = (ui: ReactNode) => render( - - - - {ui} - - + + + + {ui} + + + , ); @@ -38,16 +38,16 @@ describe('ErrorCatcher', () => { useNavigate: jest.fn(), })); - it('์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์—๋Ÿฌ์ธ ๊ฒฝ์šฐ ํ† ์ŠคํŠธ๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.', async () => { - const predictableErrorCode = 'EVENT_NOT_FOUND'; - const error = new RequestError({ - message: '์„œ๋ฒ„์˜ ์—๋Ÿฌ๋ฉ”์„ธ์ง€', - name: predictableErrorCode, + it('ํ•ธ๋“ค๋ง ๊ฐ€๋Šฅํ•œ ์—๋Ÿฌ์ธ ๊ฒฝ์šฐ ํ† ์ŠคํŠธ๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.', async () => { + const errorCode = 'EVENT_NOT_FOUND'; + const error = new FetchError({ + errorInfo: {errorCode, message: '์„œ๋ฒ„์˜ ์—๋Ÿฌ๋ฉ”์„ธ์ง€'}, + name: errorCode, + message: '์—๋Ÿฌ๋ฉ”์„ธ์ง€', status: 200, endpoint: '', method: 'GET', requestBody: '', - errorCode: predictableErrorCode, }); const {updateAppError} = useAppErrorStore.getState(); @@ -58,7 +58,7 @@ describe('ErrorCatcher', () => { screen.getByText('Trigger Error').click(); }); - const errorMessage = SERVER_ERROR_MESSAGES[predictableErrorCode]; + const errorMessage = SERVER_ERROR_MESSAGES[errorCode]; await waitFor(() => { expect(screen.getByText(errorMessage)).toBeInTheDocument(); @@ -66,15 +66,15 @@ describe('ErrorCatcher', () => { }); it('ํ•ธ๋“ค๋ง ๋ถˆ๊ฐ€๋Šฅํ•œ ์—๋Ÿฌ์ธ ๊ฒฝ์šฐ ์—๋Ÿฌ ๋ฐ”์šด๋”๋ฆฌ๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.', async () => { - const unPredictableErrorCode = '๋ชจ๋ฅด๊ฒ ๋Š” ์—๋Ÿฌ'; - const error = new RequestError({ - message: '๋ชจ๋ฅด๊ฒ ๋Š” ์—๋Ÿฌ๋ฉ”์„ธ์ง€', - name: unPredictableErrorCode, + const errorCode = '๋ชจ๋ฅด๊ฒ ๋Š” ์—๋Ÿฌ'; + const error = new FetchError({ + errorInfo: {errorCode, message: '๋ชจ๋ฅด๊ฒ ๋Š” ์—๋Ÿฌ๋ฉ”์„ธ์ง€'}, + name: errorCode, + message: '์—๋Ÿฌ๋ฉ”์„ธ์ง€', status: 400, endpoint: '', method: 'GET', requestBody: '', - errorCode: unPredictableErrorCode, }); const {updateAppError} = useAppErrorStore.getState(); diff --git a/client/src/components/AppErrorBoundary/ErrorCatcher.tsx b/client/src/components/AppErrorBoundary/ErrorCatcher.tsx index 9cb179602..dde5f3d64 100644 --- a/client/src/components/AppErrorBoundary/ErrorCatcher.tsx +++ b/client/src/components/AppErrorBoundary/ErrorCatcher.tsx @@ -1,36 +1,60 @@ import {useEffect} from 'react'; -import toast from '@hooks/useToast/toast'; +import FetchError from '@errors/FetchError'; +import {useToast} from '@hooks/useToast/useToast'; import {useAppErrorStore} from '@store/appErrorStore'; import {captureError} from '@utils/captureError'; -import isRequestError from '@utils/isRequestError'; -import {SERVER_ERROR_MESSAGES} from '@constants/errorMessage'; +import {SERVER_ERROR_MESSAGES, UNKNOWN_ERROR} from '@constants/errorMessage'; -const isPredictableError = (error: Error) => { - if (isRequestError(error)) if (error.errorCode === 'INTERNAL_SERVER_ERROR') return false; - - return SERVER_ERROR_MESSAGES[error.name] !== undefined; +export type ErrorInfo = { + errorCode: string; + message: string; }; -const ErrorCatcher = ({children}: React.PropsWithChildren) => { - const {appError: error} = useAppErrorStore(); +const convertAppErrorToErrorInfo = (appError: Error) => { + if (appError instanceof Error) { + const errorInfo = + appError instanceof FetchError ? appError.errorInfo : {errorCode: appError.name, message: appError.message}; - useEffect(() => { - if (!error) return; + return errorInfo; + } else { + const errorInfo = {errorCode: UNKNOWN_ERROR, message: JSON.stringify(appError)}; - captureError(error); + return errorInfo; + } +}; - if (!isRequestError(error) || !isPredictableError(error)) throw error; +const isUnhandledError = (errorInfo: ErrorInfo) => { + if (errorInfo.errorCode === 'INTERNAL_SERVER_ERROR') return true; - toast.error(SERVER_ERROR_MESSAGES[error.errorCode], { - showingTime: 3000, - position: 'bottom', - bottom: '8rem', - }); - }, [error]); + return SERVER_ERROR_MESSAGES[errorInfo.errorCode] === undefined; +}; + +const ErrorCatcher = ({children}: React.PropsWithChildren) => { + const {appError} = useAppErrorStore(); + const {showToast} = useToast(); + + useEffect(() => { + if (appError) { + const errorInfo = convertAppErrorToErrorInfo(appError); + captureError(appError, errorInfo); + + if (!isUnhandledError(errorInfo)) { + showToast({ + showingTime: 3000, + message: SERVER_ERROR_MESSAGES[errorInfo.errorCode], + type: 'error', + position: 'bottom', + bottom: '8rem', + }); + } else { + throw appError; + } + } + }, [appError]); return children; }; diff --git a/client/src/components/BillDetails/BillDetails.tsx b/client/src/components/BillDetails/BillDetails.tsx deleted file mode 100644 index 3d9be8461..000000000 --- a/client/src/components/BillDetails/BillDetails.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import {css} from '@emotion/react'; -import {forwardRef} from 'react'; - -import EditableAmount from '@components/Design/components/Amount/EditableAmount'; -import {BillDetail} from 'types/serviceType'; - -import {Text} from '@components/Design'; - -interface Props { - billDetails: BillDetail[]; - onClickInput: (id: number) => void; - activatedId: number; -} - -const BillDetails = forwardRef(({billDetails, onClickInput, activatedId}, ref) => { - return ( -
- {billDetails.map(billDetail => ( -
- {billDetail.memberName} - - {}} - onClick={() => onClickInput(billDetail.id)} - isFixed={billDetail.isFixed} - activated={activatedId === billDetail.id} - /> -
- ))} -
- ); -}); - -export default BillDetails; diff --git a/client/src/components/Logo/Logo.style.ts b/client/src/components/Common/Logo/Logo.style.ts similarity index 100% rename from client/src/components/Logo/Logo.style.ts rename to client/src/components/Common/Logo/Logo.style.ts diff --git a/client/src/components/Logo/RunningDogLogo.tsx b/client/src/components/Common/Logo/RunningDogLogo.tsx similarity index 100% rename from client/src/components/Logo/RunningDogLogo.tsx rename to client/src/components/Common/Logo/RunningDogLogo.tsx diff --git a/client/src/components/Logo/StandingDogLogo.tsx b/client/src/components/Common/Logo/StandingDogLogo.tsx similarity index 100% rename from client/src/components/Logo/StandingDogLogo.tsx rename to client/src/components/Common/Logo/StandingDogLogo.tsx diff --git a/client/src/components/Logo/index.ts b/client/src/components/Common/Logo/index.ts similarity index 100% rename from client/src/components/Logo/index.ts rename to client/src/components/Common/Logo/index.ts diff --git a/client/src/components/Design/components/Amount/Amount.stories.tsx b/client/src/components/Design/components/Amount/Amount.stories.tsx deleted file mode 100644 index bb9ce5b5c..000000000 --- a/client/src/components/Design/components/Amount/Amount.stories.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import Amount from '@HDcomponents/Amount/Amount'; - -const meta = { - title: 'Components/Amount', - component: Amount, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - amount: { - description: '', - control: {type: 'number'}, - }, - }, - args: { - amount: 112000, - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = {}; diff --git a/client/src/components/Design/components/Amount/Amount.tsx b/client/src/components/Design/components/Amount/Amount.tsx deleted file mode 100644 index c07fe1ae3..000000000 --- a/client/src/components/Design/components/Amount/Amount.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {css} from '@emotion/react'; - -import Flex from '../Flex/Flex'; -import Text from '../Text/Text'; - -interface Props { - amount: number; -} - -const Amount = ({amount}: Props) => { - return ( -
- {amount ? amount.toLocaleString('ko-kr') : 0} - - ์› - -
- ); -}; - -export default Amount; diff --git a/client/src/components/Design/components/Amount/EditableAmount.tsx b/client/src/components/Design/components/Amount/EditableAmount.tsx deleted file mode 100644 index c71ed1778..000000000 --- a/client/src/components/Design/components/Amount/EditableAmount.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import {css} from '@emotion/react'; -import {useEffect, useRef, useState} from 'react'; - -import {useTheme} from '@components/Design/theme/HDesignProvider'; -import TYPOGRAPHY from '@components/Design/token/typography'; - -import Icon from '../Icon/Icon'; -import Text from '../Text/Text'; - -interface Props { - value: string; - onChange?: (event: React.ChangeEvent) => void; - onClick?: () => void; - readOnly?: boolean; - isFixed?: boolean; - activated?: boolean; -} - -const EditableAmount = ({value, onChange, onClick, readOnly = true, isFixed = false, activated}: Props) => { - const {theme} = useTheme(); - - const [width, setWidth] = useState(0); - - const spanRef = useRef(null); - - useEffect(() => { - if (spanRef.current) { - setWidth(spanRef.current.getBoundingClientRect().width); - } - }, [value]); - - return ( - - ); -}; - -export default EditableAmount; diff --git a/client/src/components/Design/components/BankSelect/BankSelect.stories.tsx b/client/src/components/Design/components/BankSelect/BankSelect.stories.tsx deleted file mode 100644 index d7b6f88f6..000000000 --- a/client/src/components/Design/components/BankSelect/BankSelect.stories.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import BankSelect from './BankSelect'; - -const meta = { - title: 'Components/BankSelect', - component: BankSelect, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - argTypes: {}, - args: { - onSelect: (name: string) => alert(name), - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = {}; diff --git a/client/src/components/Design/components/BankSelect/BankSelect.style.ts b/client/src/components/Design/components/BankSelect/BankSelect.style.ts deleted file mode 100644 index 5c42e3909..000000000 --- a/client/src/components/Design/components/BankSelect/BankSelect.style.ts +++ /dev/null @@ -1,31 +0,0 @@ -import {css} from '@emotion/react'; - -import ImageSprite from '@assets/image/banksprite.png'; - -export const iconStyle = (position: string) => - css({ - width: '80px', - height: '80px', - background: `url(${ImageSprite}) ${position}`, - }); - -export const bankSelectStyle = css({ - display: 'grid', - gridTemplateColumns: 'repeat(3, 1fr)', - gridRowGap: '1rem', - gridColumnGap: '2rem', - placeItems: 'center', - - height: '100%', - - '@media (min-width: 450px)': { - gridTemplateColumns: 'repeat(4, 1fr)', - }, - - overflowY: 'scroll', - scrollbarWidth: 'none', - - '&::-webkit-scrollbar': { - display: 'none', - }, -}); diff --git a/client/src/components/Design/components/BankSelect/BankSelect.tsx b/client/src/components/Design/components/BankSelect/BankSelect.tsx deleted file mode 100644 index 5fdc6f2df..000000000 --- a/client/src/components/Design/components/BankSelect/BankSelect.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import BANKS from '@constants/bank'; - -import Text from '../Text/Text'; -import Flex from '../Flex/Flex'; - -import {bankSelectStyle, iconStyle} from './BankSelect.style'; - -type BankSelectProps = { - onSelect: (name: string) => void; -}; - -const BankSelect = ({onSelect}: BankSelectProps) => { - return ( -
- {BANKS.map(({name, iconPosition}) => ( - - ))} -
- ); -}; - -export default BankSelect; diff --git a/client/src/components/Design/components/BankSendButton/BankSelect.stories.tsx b/client/src/components/Design/components/BankSendButton/BankSelect.stories.tsx deleted file mode 100644 index 3d68811ae..000000000 --- a/client/src/components/Design/components/BankSendButton/BankSelect.stories.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import BankSendButton from './BankSendButton'; - -const meta = { - title: 'Components/BankSendButton', - component: BankSendButton, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - argTypes: { - isDeposited: { - description: '', - control: {type: 'boolean'}, - }, - }, - args: { - clipboardText: 'ํ† ์Šค๋ฑ…ํฌ 010100-10-123123', - onBankButtonClick: () => console.log('์•ˆ๋…•'), - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = {}; diff --git a/client/src/components/Design/components/BankSendButton/BankSendButton.style.ts b/client/src/components/Design/components/BankSendButton/BankSendButton.style.ts deleted file mode 100644 index bb6bbffb7..000000000 --- a/client/src/components/Design/components/BankSendButton/BankSendButton.style.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@components/Design/theme/theme.type'; - -export const bankButtonStyle = (theme: Theme) => - css({ - width: '3.25rem', - height: '1.5rem', - - backgroundColor: theme.colors.tertiary, - - borderRadius: '0.5rem', - }); - -export const isDepositedStyle = (theme: Theme) => - css({ - width: '3.25rem', - height: '1.5rem', - - backgroundColor: theme.colors.grayContainer, - - borderRadius: '0.5rem', - }); diff --git a/client/src/components/Design/components/BankSendButton/BankSendButton.tsx b/client/src/components/Design/components/BankSendButton/BankSendButton.tsx deleted file mode 100644 index 3351b7dcc..000000000 --- a/client/src/components/Design/components/BankSendButton/BankSendButton.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import CopyToClipboard from 'react-copy-to-clipboard'; - -import {useTheme} from '@components/Design/theme/HDesignProvider'; - -import Icon from '../Icon/Icon'; -import Text from '../Text/Text'; -import Flex from '../Flex/Flex'; - -import {bankButtonStyle, isDepositedStyle} from './BankSendButton.style'; - -type BankSendButtonProps = React.HTMLAttributes & { - clipboardText: string; - onBankButtonClick: () => void; - isDeposited?: boolean; -}; - -const BankSendButton = ({ - clipboardText, - onBankButtonClick, - isDeposited = false, - ...buttonProps -}: BankSendButtonProps) => { - const {theme} = useTheme(); - - return isDeposited ? ( - - ) : ( - - - - ); -}; - -export default BankSendButton; diff --git a/client/src/components/Design/components/Chip/Chip.stories.tsx b/client/src/components/Design/components/Chip/Chip.stories.tsx deleted file mode 100644 index 08e7f259c..000000000 --- a/client/src/components/Design/components/Chip/Chip.stories.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import Chip from '@HDcomponents/Chip/Chip'; - -import Text from '../Text/Text'; -import Amount from '../Amount/Amount'; - -const meta = { - title: 'Components/Chip', - component: Chip, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - color: { - description: '', - control: {type: 'select'}, - }, - text: { - description: '', - control: {type: 'text'}, - }, - }, - args: { - color: 'gray', - text: '๋ง์ตธ', - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = {}; diff --git a/client/src/components/Design/components/Chip/Chip.style.ts b/client/src/components/Design/components/Chip/Chip.style.ts deleted file mode 100644 index a7ca3eaf7..000000000 --- a/client/src/components/Design/components/Chip/Chip.style.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {css} from '@emotion/react'; - -import {ColorKeys} from '@components/Design/token/colors'; -import {Theme} from '@theme/theme.type'; - -interface ChipStyleProps { - theme: Theme; - color: ColorKeys; -} - -export const chipStyle = ({theme, color}: ChipStyleProps) => - css({ - display: 'flex', - padding: '0.125rem 0.5rem ', - borderRadius: '0.5rem', - color: `${theme.colors[color]}`, - boxSizing: 'border-box', - outline: 'none', - boxShadow: `inset 0 0 0 1px ${theme.colors[color]}`, - }); diff --git a/client/src/components/Design/components/Chip/Chip.tsx b/client/src/components/Design/components/Chip/Chip.tsx deleted file mode 100644 index 9566dfe7e..000000000 --- a/client/src/components/Design/components/Chip/Chip.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import {ColorKeys} from '@components/Design/token/colors'; -import {useTheme} from '@components/Design/theme/HDesignProvider'; - -import Text from '../Text/Text'; - -import {chipStyle} from './Chip.style'; - -interface Props { - color: ColorKeys; - text: string; -} - -const Chip = ({color, text}: Props) => { - const {theme} = useTheme(); - return ( -
- - {text} - -
- ); -}; - -export default Chip; diff --git a/client/src/components/Design/components/ChipButton/ChipButton.stories.tsx b/client/src/components/Design/components/ChipButton/ChipButton.stories.tsx deleted file mode 100644 index b3d3ea534..000000000 --- a/client/src/components/Design/components/ChipButton/ChipButton.stories.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import ChipButton from '@HDcomponents/ChipButton/ChipButton'; - -const meta = { - title: 'Components/ChipButton', - component: ChipButton, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - color: { - description: '', - control: {type: 'select'}, - }, - text: { - description: '', - control: {type: 'text'}, - }, - }, - args: { - color: 'gray', - text: '๋ง์ตธ', - onClick: () => {}, - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = {}; diff --git a/client/src/components/Design/components/ChipButton/ChipButton.style.ts b/client/src/components/Design/components/ChipButton/ChipButton.style.ts deleted file mode 100644 index ec0a19c0b..000000000 --- a/client/src/components/Design/components/ChipButton/ChipButton.style.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {css} from '@emotion/react'; - -import {ColorKeys} from '@components/Design/token/colors'; -import {Theme} from '@theme/theme.type'; - -interface ChipStyleProps { - theme: Theme; - color: ColorKeys; -} - -export const chipButtonStyle = ({theme, color}: ChipStyleProps) => - css({ - display: 'flex', - padding: '0.25rem 0.375rem 0.25rem 0.75rem', - gap: '0.5rem', - borderRadius: '1rem', - color: `${theme.colors[color]}`, - boxSizing: 'border-box', - outline: 'none', - boxShadow: `inset 0 0 0 1px ${theme.colors[color]}`, - }); diff --git a/client/src/components/Design/components/ChipButton/ChipButton.tsx b/client/src/components/Design/components/ChipButton/ChipButton.tsx deleted file mode 100644 index 7b0e1aa50..000000000 --- a/client/src/components/Design/components/ChipButton/ChipButton.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import {ColorKeys} from '@components/Design/token/colors'; -import {useTheme} from '@components/Design/theme/HDesignProvider'; - -import Text from '../Text/Text'; -import Icon from '../Icon/Icon'; - -import {chipButtonStyle} from './ChipButton.style'; - -interface Props { - color: ColorKeys; - text: string; - onClick: () => void; -} - -const ChipButton = ({color, text, onClick}: Props) => { - const {theme} = useTheme(); - return ( -
- {text} - -
- ); -}; - -export default ChipButton; diff --git a/client/src/components/Design/components/ChipGroup/ChipGroup.stories.tsx b/client/src/components/Design/components/ChipGroup/ChipGroup.stories.tsx deleted file mode 100644 index f60a84a01..000000000 --- a/client/src/components/Design/components/ChipGroup/ChipGroup.stories.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import ChipGroup from '@HDcomponents/ChipGroup/ChipGroup'; - -const meta = { - title: 'Components/ChipGroup', - component: ChipGroup, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - color: { - description: '', - control: {type: 'select'}, - }, - }, - args: { - color: 'gray', - texts: ['๋ง์ตธ', '๊ฐ์ž', '๋ฐฑํ˜ธ', '์ด์ƒ'], - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = {}; diff --git a/client/src/components/Design/components/ChipGroup/ChipGroup.style.ts b/client/src/components/Design/components/ChipGroup/ChipGroup.style.ts deleted file mode 100644 index fcd3433ee..000000000 --- a/client/src/components/Design/components/ChipGroup/ChipGroup.style.ts +++ /dev/null @@ -1,8 +0,0 @@ -import {css} from '@emotion/react'; - -export const chipGroupStyle = css({ - display: 'flex', - gap: '0.25rem', - flexWrap: 'wrap', - overflow: 'hidden', -}); diff --git a/client/src/components/Design/components/ChipGroup/ChipGroup.tsx b/client/src/components/Design/components/ChipGroup/ChipGroup.tsx deleted file mode 100644 index 792228217..000000000 --- a/client/src/components/Design/components/ChipGroup/ChipGroup.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import {ColorKeys} from '@components/Design/token/colors'; -import {useTheme} from '@components/Design/theme/HDesignProvider'; - -import {chipStyle} from '../Chip/Chip.style'; -import Text from '../Text/Text'; -import Chip from '../Chip/Chip'; - -import {chipGroupStyle} from './ChipGroup.style'; - -interface Props { - color: ColorKeys; - texts: string[]; -} - -const ChipGroup = ({color, texts}: Props) => { - return ( -
- {texts.map(text => ( - - ))} -
- ); -}; - -export default ChipGroup; diff --git a/client/src/components/Design/components/DepositCheck/DepositCheck.stories.tsx b/client/src/components/Design/components/DepositCheck/DepositCheck.stories.tsx deleted file mode 100644 index 7cfd25aea..000000000 --- a/client/src/components/Design/components/DepositCheck/DepositCheck.stories.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import DepositCheck from '@HDcomponents/DepositCheck/DepositCheck'; - -const meta = { - title: 'Components/DepositCheck', - component: DepositCheck, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - isDeposited: { - description: '', - control: {type: 'boolean'}, - }, - }, - args: { - isDeposited: false, - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = {}; diff --git a/client/src/components/Design/components/DepositCheck/DepositCheck.style.ts b/client/src/components/Design/components/DepositCheck/DepositCheck.style.ts deleted file mode 100644 index 22f1f52a9..000000000 --- a/client/src/components/Design/components/DepositCheck/DepositCheck.style.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {css} from '@emotion/react'; - -import {WithTheme} from '@components/Design/type/withTheme'; - -import {DepositCheckStyleProps} from './DepositCheck.type'; - -export const DepositCheckStyle = ({theme, isDeposited}: WithTheme) => - css({ - display: 'flex', - alignItems: 'center', - gap: '0.125rem', - border: `1px solid ${isDeposited ? theme.colors.primary : theme.colors.gray}`, - borderRadius: '0.5rem', - padding: '0.25rem 0.375rem', - height: '1.25rem', - - '.deposit-check-text': { - color: isDeposited ? theme.colors.primary : theme.colors.gray, - paddingTop: '0.0625rem', - }, - }); diff --git a/client/src/components/Design/components/DepositCheck/DepositCheck.tsx b/client/src/components/Design/components/DepositCheck/DepositCheck.tsx deleted file mode 100644 index 10b21aabc..000000000 --- a/client/src/components/Design/components/DepositCheck/DepositCheck.tsx +++ /dev/null @@ -1,21 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {useTheme} from '@components/Design'; - -import Icon from '../Icon/Icon'; -import Text from '../Text/Text'; - -import {DepositCheckStyle} from './DepositCheck.style'; -import {DepositCheckProps} from './DepositCheck.type'; - -const DepositCheck: React.FC = ({isDeposited = false}: DepositCheckProps) => { - const {theme} = useTheme(); - return ( -
- - ์ž…๊ธˆ - - -
- ); -}; -export default DepositCheck; diff --git a/client/src/components/Design/components/DepositCheck/DepositCheck.type.ts b/client/src/components/Design/components/DepositCheck/DepositCheck.type.ts deleted file mode 100644 index fdb308170..000000000 --- a/client/src/components/Design/components/DepositCheck/DepositCheck.type.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface DepositCheckStyleProps { - isDeposited: boolean; -} - -export interface DepositCheckCustomProps { - isDeposited: boolean; -} - -export type DepositCheckOptionProps = DepositCheckStyleProps & DepositCheckCustomProps; - -export type DepositCheckProps = React.ComponentProps<'div'> & DepositCheckOptionProps; diff --git a/client/src/components/Design/components/DepositToggle/DepositToggle.stories.tsx b/client/src/components/Design/components/DepositToggle/DepositToggle.stories.tsx deleted file mode 100644 index 49a85d749..000000000 --- a/client/src/components/Design/components/DepositToggle/DepositToggle.stories.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import {useEffect, useState} from 'react'; - -import DepositToggle from './DepositToggle'; - -const meta = { - title: 'Components/DepositToggle', - component: DepositToggle, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - isDeposit: { - description: '', - control: {type: 'boolean'}, - }, - onToggle: { - description: '', - control: {type: 'select'}, - options: [undefined, () => alert('change toggle')], - }, - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = { - args: { - isDeposit: false, - onToggle: () => {}, - }, - render: ({isDeposit, onToggle, ...args}) => { - const [isDepositState, setIsDepositState] = useState(isDeposit); - - useEffect(() => { - setIsDepositState(isDeposit); - }, [isDeposit]); - - const handleToggle = () => { - setIsDepositState(!isDepositState); - onToggle(); - }; - - return ; - }, -}; diff --git a/client/src/components/Design/components/DepositToggle/DepositToggle.style.ts b/client/src/components/Design/components/DepositToggle/DepositToggle.style.ts deleted file mode 100644 index fff882251..000000000 --- a/client/src/components/Design/components/DepositToggle/DepositToggle.style.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {css} from '@emotion/react'; - -import {WithTheme} from '@components/Design/type/withTheme'; - -import {DepositToggleStyleProps} from './DepositToggle.type'; - -export const depositToggleStyle = ({theme, isDeposit}: WithTheme) => - css({ - display: `flex`, - flexDirection: 'row', - justifyContent: 'center', - padding: '0.25rem', - borderRadius: '0.75rem', - backgroundColor: theme.colors.tertiary, - cursor: 'pointer', - alignItems: 'center', - width: '4.75rem', - height: '1.4375rem', - - '.deposit-text': { - display: 'flex', - justifyContent: 'center', - borderRadius: '0.5rem', - padding: '0 0.25rem', - zIndex: theme.zIndex.depositToggleMovingAnimation, - height: '15px', - width: '34px', - paddingTop: '0.05rem', - }, - - '.toggle-background': { - position: 'absolute', - width: '34px', - height: '15px', - borderRadius: '0.5rem', - backgroundColor: theme.colors.white, - - transition: '0.2s', - transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', - - transform: !isDeposit ? 'translateX(1.07rem)' : 'translateX(-1.06rem)', - }, - }); diff --git a/client/src/components/Design/components/DepositToggle/DepositToggle.tsx b/client/src/components/Design/components/DepositToggle/DepositToggle.tsx deleted file mode 100644 index f68353ce5..000000000 --- a/client/src/components/Design/components/DepositToggle/DepositToggle.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import {useTheme} from '@theme/HDesignProvider'; - -import Text from '../Text/Text'; - -import {DepositToggleProps} from './DepositToggle.type'; -import {depositToggleStyle} from './DepositToggle.style'; - -const DepositToggle: React.FC = ({isDeposit = false, onToggle}: DepositToggleProps) => { - const {theme} = useTheme(); - - return ( -
-
- - ์ž…๊ธˆ - - - ๋ฏธ์ž…๊ธˆ - -
- ); -}; - -export default DepositToggle; diff --git a/client/src/components/Design/components/DepositToggle/DepositToggle.type.ts b/client/src/components/Design/components/DepositToggle/DepositToggle.type.ts deleted file mode 100644 index 15f19d01f..000000000 --- a/client/src/components/Design/components/DepositToggle/DepositToggle.type.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface DepositToggleStyleProps { - isDeposit: boolean; -} - -export interface DepositToggleCustomProps { - isDeposit: boolean; - onToggle: () => void; -} - -export type DepositToggleOptionProps = DepositToggleStyleProps & DepositToggleCustomProps; - -export type DepositToggleProps = React.ComponentProps<'div'> & DepositToggleOptionProps; diff --git a/client/src/components/Design/components/Dropdown/Dropdown.stories.tsx b/client/src/components/Design/components/Dropdown/Dropdown.stories.tsx deleted file mode 100644 index 2504ecae7..000000000 --- a/client/src/components/Design/components/Dropdown/Dropdown.stories.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import Dropdown from '@HDcomponents/Dropdown/Dropdown'; - -import DropdownButton from './DropdownButton'; - -const meta = { - title: 'Components/Dropdown', - component: Dropdown, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - decorators: [ - Story => ( -
- -
- ), - ], - args: { - children: [ - alert('์ „์ฒด ์ฐธ์—ฌ์ž ๊ด€๋ฆฌ ํด๋ฆญ')} />, - alert('๊ณ„์ขŒ๋ฒˆํ˜ธ ์ž…๋ ฅํ•˜๊ธฐ ํด๋ฆญ')} />, - ], - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = {}; diff --git a/client/src/components/Design/components/Dropdown/Dropdown.style.ts b/client/src/components/Design/components/Dropdown/Dropdown.style.ts deleted file mode 100644 index 8b4fc91df..000000000 --- a/client/src/components/Design/components/Dropdown/Dropdown.style.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@components/Design/theme/theme.type'; - -import {FlexProps} from '../Flex/Flex.type'; - -export const dropdownStyle: FlexProps = { - flexDirection: 'column', - width: '12.5rem', - padding: '0.5rem', - paddingInline: '0.5rem', - gap: '0.25rem', - backgroundColor: 'white', - - otherStyle: { - position: 'absolute', - top: '2rem', - right: '-1rem', - borderRadius: '0.75rem', - boxShadow: '2px 4px 16px 0 rgba(0, 0, 0, 0.08)', - }, -}; - -export const dropdownButtonStyle = (theme: Theme) => - css({ - height: '2rem', - padding: '0.25rem 0.5rem', - - ':hover': { - borderRadius: '0.625rem', - backgroundColor: theme.colors.grayContainer, - }, - }); diff --git a/client/src/components/Design/components/Dropdown/Dropdown.tsx b/client/src/components/Design/components/Dropdown/Dropdown.tsx deleted file mode 100644 index 63045dd56..000000000 --- a/client/src/components/Design/components/Dropdown/Dropdown.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import Icon from '../Icon/Icon'; -import IconButton from '../IconButton/IconButton'; -import Flex from '../Flex/Flex'; - -import useDropdown from './useDropdown'; -import {DropdownProps} from './Dropdown.type'; -import DropdownButton from './DropdownButton'; -import {dropdownStyle} from './Dropdown.style'; - -const Dropdown = ({children}: DropdownProps) => { - const {isOpen, openDropdown, meetBallsRef, dropdownRef} = useDropdown(); - const isDropdownOpen = isOpen && meetBallsRef.current; - - return ( - - - {isDropdownOpen && ( -
- - {children.map(button => ( - - ))} - -
- )} -
- ); -}; - -export default Dropdown; diff --git a/client/src/components/Design/components/Dropdown/Dropdown.type.ts b/client/src/components/Design/components/Dropdown/Dropdown.type.ts deleted file mode 100644 index 1b67bbc33..000000000 --- a/client/src/components/Design/components/Dropdown/Dropdown.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type DropdownButtonProps = React.HTMLAttributes & { - text: string; -}; - -export type DropdownProps = { - children: React.ReactElement[]; -}; diff --git a/client/src/components/Design/components/Dropdown/DropdownButton.tsx b/client/src/components/Design/components/Dropdown/DropdownButton.tsx deleted file mode 100644 index 005a6042a..000000000 --- a/client/src/components/Design/components/Dropdown/DropdownButton.tsx +++ /dev/null @@ -1,21 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import {useTheme} from '@components/Design/theme/HDesignProvider'; - -import Text from '../Text/Text'; - -import {dropdownButtonStyle} from './Dropdown.style'; -import {DropdownButtonProps} from './Dropdown.type'; - -const DropdownButton = ({text, ...buttonProps}: DropdownButtonProps) => { - const {theme} = useTheme(); - return ( - - ); -}; - -export default DropdownButton; diff --git a/client/src/components/Design/components/Dropdown/useDropdown.ts b/client/src/components/Design/components/Dropdown/useDropdown.ts deleted file mode 100644 index f484c62a0..000000000 --- a/client/src/components/Design/components/Dropdown/useDropdown.ts +++ /dev/null @@ -1,39 +0,0 @@ -import {useEffect, useRef, useState} from 'react'; - -const useDropdown = () => { - const [isOpen, setIsOpen] = useState(false); - const meetBallsRef = useRef(null); - const dropdownRef = useRef(null); - - const openDropdown = () => { - setIsOpen(true); - }; - - useEffect(() => { - const clickOutSide = (event: MouseEvent) => { - const targetNode = event.target as Node; - - if ( - (dropdownRef.current && dropdownRef.current.contains(targetNode)) || - (meetBallsRef.current && meetBallsRef.current.contains(targetNode)) - ) { - return; - } - - setIsOpen(false); - }; - document.addEventListener('mousedown', clickOutSide); - return () => { - document.removeEventListener('mousedown', clickOutSide); - }; - }, [dropdownRef]); - - return { - isOpen, - openDropdown, - meetBallsRef, - dropdownRef, - }; -}; - -export default useDropdown; diff --git a/client/src/components/Design/components/ExpenseList/ExpenseList.stories.tsx b/client/src/components/Design/components/ExpenseList/ExpenseList.stories.tsx deleted file mode 100644 index ddaf1d50b..000000000 --- a/client/src/components/Design/components/ExpenseList/ExpenseList.stories.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import ExpenseList from '@HDcomponents/ExpenseList/ExpenseList'; - -const meta = { - title: 'Components/ExpenseList', - component: ExpenseList, - tags: ['autodocs'], - argTypes: { - expenseList: { - description: '', - }, - }, - args: { - memberName: '์†Œํ•˜', - onSearch: () => console.log('์ฟ ํ‚ค'), - placeholder: '์•ˆ๋…•', - - expenseList: [ - { - memberId: 1, - memberName: '์†Œํ•˜', - price: 2000, - isDeposited: true, - clipboardText: 'ํ† ์Šค์€ํ–‰ 2000์›', - onBankButtonClick: () => console.log('์†Œํ•˜'), - }, - { - memberId: 2, - memberName: 'ํ† ๋‹ค๋ฆฌ', - price: 2000, - isDeposited: false, - clipboardText: 'ํ† ์Šค์€ํ–‰ 2000์›', - onBankButtonClick: () => console.log('ํ† ๋‹ค๋ฆฌ'), - }, - { - memberId: 3, - memberName: '์›จ๋””', - price: 1080, - isDeposited: true, - clipboardText: 'ํ† ์Šค์€ํ–‰ 1080์›', - onBankButtonClick: () => console.log('์›จ๋””'), - }, - { - memberId: 4, - memberName: '์ฟ ํ‚ค', - price: 3020, - isDeposited: false, - clipboardText: 'ํ† ์Šค์€ํ–‰ 3020์›', - onBankButtonClick: () => console.log('์ฟ ํ‚ค'), - }, - ], - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = {}; diff --git a/client/src/components/Design/components/ExpenseList/ExpenseList.tsx b/client/src/components/Design/components/ExpenseList/ExpenseList.tsx deleted file mode 100644 index f34cc1aaf..000000000 --- a/client/src/components/Design/components/ExpenseList/ExpenseList.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import Text from '@HDcomponents/Text/Text'; - -import {isMobileDevice} from '@utils/detectDevice'; - -import BankSendButton from '../BankSendButton/BankSendButton'; -import Icon from '../Icon/Icon'; -import IconButton from '../IconButton/IconButton'; -import Flex from '../Flex/Flex'; -import Input from '../Input/Input'; -import Amount from '../Amount/Amount'; -import DepositCheck from '../DepositCheck/DepositCheck'; - -import {ExpenseItemProps, ExpenseListProps} from './ExpenseList.type'; - -function ExpenseItem({ - memberName, - price, - isDeposited, - onBankButtonClick, - clipboardText, - ...divProps -}: ExpenseItemProps) { - return ( - - - - - {memberName} - - - - - {isMobileDevice() ? ( - - ) : ( - - - - )} - - - ); -} - -function ExpenseList({memberName, onSearch, placeholder, expenseList = []}: ExpenseListProps) { - return ( - - - {expenseList.length !== 0 && expenseList.map(expense => )} - - ); -} - -export default ExpenseList; diff --git a/client/src/components/Design/components/ExpenseList/ExpenseList.type.ts b/client/src/components/Design/components/ExpenseList/ExpenseList.type.ts deleted file mode 100644 index 90a44c842..000000000 --- a/client/src/components/Design/components/ExpenseList/ExpenseList.type.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {Report} from 'types/serviceType'; - -export type ExpenseItemCustomProps = Report & { - onBankButtonClick: () => void; - clipboardText: string; -}; - -export type ExpenseItemProps = React.ComponentProps<'div'> & ExpenseItemCustomProps; - -export type ExpenseListProps = { - memberName: string; - onSearch: ({target}: React.ChangeEvent) => void; - placeholder: string; - expenseList: ExpenseItemProps[]; -}; diff --git a/client/src/components/Design/components/Icon/Icon.tsx b/client/src/components/Design/components/Icon/Icon.tsx deleted file mode 100644 index d59a08bc4..000000000 --- a/client/src/components/Design/components/Icon/Icon.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import Toss from '@assets/image/Toss_Symbol_Primary.png'; -import InputDelete from '@assets/image/inputDelete.svg'; -import Buljusa from '@assets/image/buljusa.svg'; -import Error from '@assets/image/error.svg'; -import Confirm from '@assets/image/confirm.svg'; -import Trash from '@assets/image/trash.svg'; -import TrashMini from '@assets/image/trash_mini.svg'; -import Search from '@assets/image/search.svg'; -import RightChevron from '@assets/image/rightChevron.svg'; -import Check from '@assets/image/check.svg'; -import X from '@assets/image/x.svg'; -import PencilMini from '@assets/image/pencil_mini.svg'; -import Meatballs from '@assets/image/meatballs.svg'; -import EditPencil from '@assets/image/editPencil.svg'; -import Heundeut from '@assets/image/heundeut.svg'; -import {IconProps} from '@HDcomponents/Icon/Icon.type'; -import {useTheme} from '@theme/HDesignProvider'; - -import {iconStyle} from './Icon.style'; - -const ICON = { - inputDelete: , - buljusa: , - rightChevron: , - search: , - error: , - confirm: , - trash: , - trashMini: , - check: , - x: , - pencilMini: , - toss: toss icon, - meatballs: , - editPencil: , - heundeut: , -}; - -export const Icon: React.FC = ({iconColor, iconType, ...htmlProps}: IconProps) => { - const {theme} = useTheme(); - return ( -
- {ICON[iconType]} -
- ); -}; - -export default Icon; diff --git a/client/src/components/Design/components/ListItem/ListItem.stories.tsx b/client/src/components/Design/components/ListItem/ListItem.stories.tsx deleted file mode 100644 index 5d7f12e1c..000000000 --- a/client/src/components/Design/components/ListItem/ListItem.stories.tsx +++ /dev/null @@ -1,37 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import ListItem from '@HDcomponents/ListItem/ListItem'; - -import Text from '../Text/Text'; -import Amount from '../Amount/Amount'; - -const meta = { - title: 'Components/ListItem', - component: ListItem, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: {}, - args: {}, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = { - render: ({...args}) => { - return ( -
- - - ๋ฝ•์Ÿ์ด ์กฑ๋ฐœ - - - -
- ); - }, -}; diff --git a/client/src/components/Design/components/ListItem/ListItem.style.ts b/client/src/components/Design/components/ListItem/ListItem.style.ts deleted file mode 100644 index 755feab36..000000000 --- a/client/src/components/Design/components/ListItem/ListItem.style.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@components/Design/theme/theme.type'; - -export const listItemStyle = (theme: Theme) => - css({ - display: 'flex', - flexDirection: 'column', - width: '100%', - gap: '0.5rem', - backgroundColor: theme.colors.white, - padding: '0.5rem 1rem', - borderRadius: '0.75rem', - }); - -export const rowStyle = (theme: Theme) => - css({ - display: 'flex', - width: '100%', - justifyContent: 'space-between', - }); diff --git a/client/src/components/Design/components/ListItem/ListItem.tsx b/client/src/components/Design/components/ListItem/ListItem.tsx deleted file mode 100644 index 261dd1f75..000000000 --- a/client/src/components/Design/components/ListItem/ListItem.tsx +++ /dev/null @@ -1,18 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {useTheme} from '@components/Design/theme/HDesignProvider'; - -import {listItemStyle} from './ListItem.style'; -import Row from './Row'; - -const ListItem = ({children, ...rest}: React.HTMLAttributes) => { - const {theme} = useTheme(); - return ( -
- {children} -
- ); -}; - -ListItem.Row = Row; - -export default ListItem; diff --git a/client/src/components/Design/components/ListItem/Row.tsx b/client/src/components/Design/components/ListItem/Row.tsx deleted file mode 100644 index 9cd9a3d1a..000000000 --- a/client/src/components/Design/components/ListItem/Row.tsx +++ /dev/null @@ -1,15 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {useTheme} from '@components/Design/theme/HDesignProvider'; - -import {rowStyle} from './ListItem.style'; - -const Row = ({children, ...rest}: React.HTMLAttributes) => { - const {theme} = useTheme(); - return ( -
- {children} -
- ); -}; - -export default Row; diff --git a/client/src/components/Design/components/NumberKeyboard/Keypad.tsx b/client/src/components/Design/components/NumberKeyboard/Keypad.tsx deleted file mode 100644 index 3f41fad95..000000000 --- a/client/src/components/Design/components/NumberKeyboard/Keypad.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {css} from '@emotion/react'; - -import {setDarker, setLighter} from '@components/Design/utils/colors'; - -import {Text, useTheme} from '@components/Design'; - -interface Props { - value: string; - onClick: () => void; - disabled?: boolean; -} - -export function Keypad({value, onClick, disabled = false}: Props) { - const {theme} = useTheme(); - return ( - - ); -} diff --git a/client/src/components/Design/components/NumberKeyboard/NumberKeyboard.stories.tsx b/client/src/components/Design/components/NumberKeyboard/NumberKeyboard.stories.tsx deleted file mode 100644 index 0778c506f..000000000 --- a/client/src/components/Design/components/NumberKeyboard/NumberKeyboard.stories.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import {useRef, useState} from 'react'; - -import {Flex, Input} from '@components/Design'; - -import RULE from '@constants/rule'; - -import NumberKeyboard from './NumberKeyboard'; - -const meta = { - title: 'Components/NumberKeyboard', - component: NumberKeyboard, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - type: {description: '', control: {type: 'select'}, options: ['amount', 'number', 'string']}, - }, - args: { - type: 'amount', - maxNumber: RULE.maxPrice, - onChange: () => {}, - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = { - render: ({type, maxNumber}) => { - const inputRef = useRef(null); - const [value, setValue] = useState(''); - return ( - - - - - ); - }, -}; diff --git a/client/src/components/Design/components/NumberKeyboard/NumberKeyboard.tsx b/client/src/components/Design/components/NumberKeyboard/NumberKeyboard.tsx deleted file mode 100644 index bc8d499df..000000000 --- a/client/src/components/Design/components/NumberKeyboard/NumberKeyboard.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {css} from '@emotion/react'; - -import {Button, useTheme} from '@components/Design'; - -import {Keypad} from './Keypad'; -import useNumberKeyboard from './useNumberKeyboard'; - -export type KeyboardType = 'number' | 'string' | 'amount'; - -export interface NumberKeyboardProps { - type: KeyboardType; - maxNumber: number; - initialValue?: string; - onChange: (value: string) => void; -} - -export default function NumberKeyboard({type, maxNumber, initialValue, onChange}: NumberKeyboardProps) { - const {theme} = useTheme(); - const amountKeypads = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '00', '0', '<-']; - const numberKeypads = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '', '0', '<-']; - - const {onClickKeypad, onClickDelete, onClickDeleteAll, onClickAddAmount} = useNumberKeyboard({ - type, - initialValue, - maxNumber, - onChange, - }); - - return ( -
- {type === 'amount' && ( -
- - - - -
- )} - {(type === 'amount' ? amountKeypads : numberKeypads).map(el => ( - onClickKeypad(el)} - /> - ))} -
- ); -} diff --git a/client/src/components/Design/components/NumberKeyboard/NumberKeyboardBottomSheet.tsx b/client/src/components/Design/components/NumberKeyboard/NumberKeyboardBottomSheet.tsx deleted file mode 100644 index cf9b07ada..000000000 --- a/client/src/components/Design/components/NumberKeyboard/NumberKeyboardBottomSheet.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import {css} from '@emotion/react'; -import {createPortal} from 'react-dom'; -import {useEffect, useRef} from 'react'; - -import {useTheme} from '@components/Design/theme/HDesignProvider'; - -import FixedButton from '../FixedButton/FixedButton'; - -import NumberKeyboard, {NumberKeyboardProps} from './NumberKeyboard'; -import useNumberKeyboardBottomSheet from './useNumberKeyboardBottomSheet'; - -interface Props extends NumberKeyboardProps { - isOpened: boolean; - onClose: () => void; -} - -const NumberKeyboardBottomSheet = ({isOpened, onClose, ...props}: Props) => { - const {theme} = useTheme(); - const {bottomSheetRef} = useNumberKeyboardBottomSheet({isOpened}); - - return createPortal( -
- - - ๋‹ซ๊ธฐ - -
, - document.body, - ); -}; - -export default NumberKeyboardBottomSheet; diff --git a/client/src/components/Design/components/NumberKeyboard/useNumberKeyboard.tsx b/client/src/components/Design/components/NumberKeyboard/useNumberKeyboard.tsx deleted file mode 100644 index 1c64f61b3..000000000 --- a/client/src/components/Design/components/NumberKeyboard/useNumberKeyboard.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import {useEffect, useState} from 'react'; - -import {KeyboardType} from './NumberKeyboard'; - -interface Props { - type: KeyboardType; - maxNumber?: number; - initialValue?: string; - onChange: (value: string) => void; -} - -const useNumberKeyboard = ({type, maxNumber, initialValue, onChange}: Props) => { - const [value, setValue] = useState(initialValue ?? ''); - - useEffect(() => { - if (initialValue) { - setValue(initialValue); - } - }, [initialValue]); - - const onClickKeypad = (inputValue: string) => { - const newValue = (value + inputValue).replace(/,/g, ''); - setValueByType(newValue); - }; - - const onClickDelete = () => { - const newValue = value.slice(0, value.length - 1).replace(/,/g, ''); - setValueByType(newValue); - }; - - const onClickDeleteAll = () => { - setValue(''); - }; - - const onClickAddAmount = (amount: number) => { - const newValue = `${Number(value.replace(/,/g, '')) + amount}`; - setValueByType(newValue); - }; - - const setValueByType = (value: string) => { - if (type === 'string') { - setValue(value); - } else { - const limitedValue = maxNumber !== 0 ? (maxNumber && Number(value) > maxNumber ? `${maxNumber}` : value) : 0; - - if (Number(limitedValue) === 0) { - setValue(''); - } else { - setValue(type === 'amount' ? Number(limitedValue).toLocaleString() : `${limitedValue}`); - } - } - }; - - useEffect(() => { - onChange(value); - }, [value]); - - return {value, onClickKeypad, onClickDelete, onClickDeleteAll, onClickAddAmount}; -}; - -export default useNumberKeyboard; diff --git a/client/src/components/Design/components/NumberKeyboard/useNumberKeyboardBottomSheet.ts b/client/src/components/Design/components/NumberKeyboard/useNumberKeyboardBottomSheet.ts deleted file mode 100644 index 28e5cc6a3..000000000 --- a/client/src/components/Design/components/NumberKeyboard/useNumberKeyboardBottomSheet.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {useEffect, useRef} from 'react'; - -interface Props { - isOpened: boolean; -} - -const useNumberKeyboardBottomSheet = ({isOpened}: Props) => { - const bottomSheetRef = useRef(null); - - useEffect(() => { - const bottomSheet = bottomSheetRef.current; - if (!bottomSheet) return; - - const preventScroll = (e: TouchEvent) => { - if (bottomSheet.contains(e.target as Node)) { - e.preventDefault(); - } - }; - - if (isOpened) { - document.addEventListener('touchmove', preventScroll, {passive: false}); - } - - return () => { - document.removeEventListener('touchmove', preventScroll); - }; - }, [isOpened]); - - return {bottomSheetRef}; -}; - -export default useNumberKeyboardBottomSheet; diff --git a/client/src/components/Design/components/Tabs/Tabs.style.ts b/client/src/components/Design/components/Tabs/Tabs.style.ts deleted file mode 100644 index 842b34823..000000000 --- a/client/src/components/Design/components/Tabs/Tabs.style.ts +++ /dev/null @@ -1,63 +0,0 @@ -import {css} from '@emotion/react'; - -import {WithTheme} from '@components/Design/type/withTheme'; - -export const tabListStyle = ({theme}: WithTheme) => - css({ - position: 'relative', - - height: '3rem', - marginBottom: '0.5rem', - - borderRadius: '0.75rem', - backgroundColor: theme.colors.white, - - cursor: 'pointer', - - WebkitTapHighlightColor: 'transparent', - }); - -export const tabItemStyle = css({ - flex: 1, - - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - - height: '100%', -}); - -type WithSelected = WithTheme & { - selected: boolean; -}; - -type IndicatorType = WithTheme & { - tabWidth: number; - activeTabIndex: number; -}; - -export const tabTextStyle = ({theme, selected}: WithSelected) => - css({ - color: selected ? theme.colors.onTertiary : theme.colors.gray, - - zIndex: theme.zIndex.tabText, - }); - -export const indicatorStyle = ({theme, tabWidth, activeTabIndex}: IndicatorType) => - css({ - position: 'absolute', - bottom: '0.5rem', - left: '0.5rem', - width: `${tabWidth}px`, - height: 'calc(100% - 1rem)', - - borderRadius: '0.625rem', - backgroundColor: theme.colors.tertiary, - - transform: `translateX(${(tabWidth + 8) * activeTabIndex}px)`, - - transition: '0.2s', - transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', - - zIndex: theme.zIndex.tabIndicator, - }); diff --git a/client/src/components/Design/components/Tabs/Tabs.tsx b/client/src/components/Design/components/Tabs/Tabs.tsx deleted file mode 100644 index 8a5e3fad0..000000000 --- a/client/src/components/Design/components/Tabs/Tabs.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import React, {useEffect, useRef, useState} from 'react'; - -import {useTheme} from '@theme/HDesignProvider'; - -import Text from '../Text/Text'; -import Flex from '../Flex/Flex'; - -import {tabListStyle, tabItemStyle, tabTextStyle, indicatorStyle} from './Tabs.style'; -import {TabsProps} from './Tab.type'; - -const Tabs: React.FC = ({children, tabsContainerStyle}) => { - const {theme} = useTheme(); - const [activeTabIndex, setActiveTabIndex] = useState(0); - const [tabWidth, setTabWidth] = useState(0); - const tabRef = useRef(null); - - const isActive = (index: number) => activeTabIndex === index; - - const setTabWidthResizeObserveCallback = (entries: ResizeObserverEntry[]) => { - for (const entry of entries) { - if (entry.target === tabRef.current) { - setTabWidth(entry.contentRect.width); - } - } - }; - - useEffect(() => { - const tabCurrent = tabRef.current; - - if (tabCurrent) { - const resizeObserver = new ResizeObserver(setTabWidthResizeObserveCallback); - resizeObserver.observe(tabCurrent); - - return () => { - resizeObserver.unobserve(tabCurrent); - }; - } - - // useEffect ๊ฒฝ๊ณ ๋ฌธ๊ตฌ ์ œ๊ฑฐ๋ฅผ ์œ„ํ•ด return ์ถ”๊ฐ€ (Not all code paths return a value.) - return; - }, [tabRef]); - - return ( - -
    - - {children.map((tabItem, index) => ( - - ))} - - {tabRef.current && tabWidth !== 0 &&
    } -
-
- {children[activeTabIndex].props.content} -
-
- ); -}; - -export default Tabs; diff --git a/client/src/components/Design/components/Title/Title.tsx b/client/src/components/Design/components/Title/Title.tsx deleted file mode 100644 index deab3ec4a..000000000 --- a/client/src/components/Design/components/Title/Title.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import Text from '@HDcomponents/Text/Text'; -import {amountContainerStyle, titleContainerStyle, titleStyle} from '@HDcomponents/Title/Title.style'; -import {TitleProps} from '@HDcomponents/Title/Title.type'; -import {useTheme} from '@theme/HDesignProvider'; - -import Amount from '../Amount/Amount'; - -export const Title: React.FC = ({title, amount, dropdown}: TitleProps) => { - const {theme} = useTheme(); - return ( -
-
- {title} - {dropdown} -
-
- - ์ „์ฒด ์ง€์ถœ ๊ธˆ์•ก - - -
-
- ); -}; - -export default Title; diff --git a/client/src/components/Design/components/Top/EditableLine.tsx b/client/src/components/Design/components/Top/EditableLine.tsx deleted file mode 100644 index 743fe191e..000000000 --- a/client/src/components/Design/components/Top/EditableLine.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {css} from '@emotion/react'; -import {useEffect, useRef, useState} from 'react'; - -import TYPOGRAPHY from '@components/Design/token/typography'; -import {useTheme} from '@components/Design/theme/HDesignProvider'; - -import Icon from '../Icon/Icon'; - -interface Props { - value: string; - onChange: (event: React.ChangeEvent) => void; -} - -export default function EditableLine({value, onChange}: Props) { - const {theme} = useTheme(); - const [width, setWidth] = useState(0); - - const spanRef = useRef(null); - - useEffect(() => { - if (spanRef.current) { - setWidth(spanRef.current.getBoundingClientRect().width); - } - }, [value]); - - return ( - - ); -} diff --git a/client/src/components/Design/components/Top/Line.tsx b/client/src/components/Design/components/Top/Line.tsx deleted file mode 100644 index 06669eb1b..000000000 --- a/client/src/components/Design/components/Top/Line.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {css} from '@emotion/react'; - -import Text from '../Text/Text'; - -interface Props { - text: string; - emphasize?: string[]; -} - -export default function Line({text, emphasize = []}: Props) { - const getTextElements = ({text, emphasize = []}: Props) => { - if (emphasize.length === 0) return [text]; - - const regexPattern = new RegExp(`(${emphasize.join('|')})`, 'g'); - return text.split(regexPattern).filter(Boolean); - }; - - const elements = getTextElements({text, emphasize}); - - return ( -
- {elements.map((text, index) => { - return ( - - {`${text}`} - - ); - })} -
- ); -} diff --git a/client/src/components/Design/components/Top/Top.stories.tsx b/client/src/components/Design/components/Top/Top.stories.tsx deleted file mode 100644 index 180c360cb..000000000 --- a/client/src/components/Design/components/Top/Top.stories.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import Top from '@HDcomponents/Top/Top'; - -const meta = { - title: 'Components/Top', - component: Top, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: {}, - args: {}, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = { - render: () => { - return ( - - - - - ); - }, -}; diff --git a/client/src/components/Design/components/Top/Top.tsx b/client/src/components/Design/components/Top/Top.tsx deleted file mode 100644 index 56c41eb6e..000000000 --- a/client/src/components/Design/components/Top/Top.tsx +++ /dev/null @@ -1,21 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {css} from '@emotion/react'; - -import Line from './Line'; -import EditableLine from './EditableLine'; - -Top.Line = Line; -Top.EditableLine = EditableLine; - -export default function Top({children}: React.PropsWithChildren) { - return ( -
- {children} -
- ); -} diff --git a/client/src/components/Design/components/TopNav/NavItem.style.ts b/client/src/components/Design/components/TopNav/NavItem.style.ts deleted file mode 100644 index eb65ca32f..000000000 --- a/client/src/components/Design/components/TopNav/NavItem.style.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {css} from '@emotion/react'; - -export const navItemStyle = css({ - padding: '0 0.5rem', - - ':first-of-type': { - paddingLeft: 0, - }, -}); diff --git a/client/src/components/Design/components/TopNav/NavItem.tsx b/client/src/components/Design/components/TopNav/NavItem.tsx deleted file mode 100644 index 41c38a150..000000000 --- a/client/src/components/Design/components/TopNav/NavItem.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {NavItemProps} from './NavItem.type'; - -import {useLocation, useNavigate} from 'react-router-dom'; - -import getDeletedLastPath from '@utils/getDeletedLastPath'; - -import TextButton from '../TextButton/TextButton'; - -import {navItemStyle} from './NavItem.style'; - -const NavItem = ({displayName, routePath, onHandleRouteInFunnel, noEmphasis = false, children}: NavItemProps) => { - const navigate = useNavigate(); - const location = useLocation(); - const matchPath = location.pathname.includes(routePath); - - const handleNavigation = () => { - if (onHandleRouteInFunnel) { - onHandleRouteInFunnel(); - return; - } - - switch (routePath) { - case '/': - navigate('/'); - break; - case '-1': - navigate(-1); - break; - default: - navigate(`${getDeletedLastPath(location.pathname)}${routePath}`); - break; - } - }; - - const getTextColor = () => { - if (noEmphasis) return 'gray'; - - return matchPath ? 'onTertiary' : 'gray'; - }; - - return ( -
  • - {children ? ( - children - ) : ( - - {displayName} - - )} -
  • - ); -}; - -export default NavItem; diff --git a/client/src/components/Design/components/TopNav/NavItem.type.ts b/client/src/components/Design/components/TopNav/NavItem.type.ts deleted file mode 100644 index d5b302468..000000000 --- a/client/src/components/Design/components/TopNav/NavItem.type.ts +++ /dev/null @@ -1,14 +0,0 @@ -export type NavItemOptionProps = { - displayName?: string; - onHandleRouteInFunnel?: () => void; -}; - -export type NavItemRequireProps = { - routePath: string; -}; - -export type NavItemStyleProps = { - noEmphasis?: boolean; -}; - -export type NavItemProps = NavItemRequireProps & NavItemOptionProps & NavItemStyleProps & React.PropsWithChildren; diff --git a/client/src/components/Design/components/TopNav/TopNav.style.ts b/client/src/components/Design/components/TopNav/TopNav.style.ts deleted file mode 100644 index 3c0c29c5e..000000000 --- a/client/src/components/Design/components/TopNav/TopNav.style.ts +++ /dev/null @@ -1,8 +0,0 @@ -import {css} from '@emotion/react'; - -export const topNavStyle = css({ - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - width: '100%', -}); diff --git a/client/src/components/Design/components/TopNav/TopNav.tsx b/client/src/components/Design/components/TopNav/TopNav.tsx deleted file mode 100644 index 84a7f9376..000000000 --- a/client/src/components/Design/components/TopNav/TopNav.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import NavItem from './NavItem'; -import {topNavStyle} from './TopNav.style'; - -type TopNavProps = React.PropsWithChildren & { - Element?: React.ReactNode; -}; - -const TopNav = ({children}: TopNavProps) => { - return ( - - ); -}; - -TopNav.Item = NavItem; - -export default TopNav; diff --git a/client/src/components/Design/index.tsx b/client/src/components/Design/index.tsx deleted file mode 100644 index a75245994..000000000 --- a/client/src/components/Design/index.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import {MainLayout} from './layouts/MainLayout'; -import FunnelLayout from './layouts/FunnelLayout'; -import {ContentLayout} from './layouts/ContentLayout'; -import {HDesignProvider, useTheme} from './theme/HDesignProvider'; -import BankSelect from './components/BankSelect/BankSelect'; -import BottomSheet from './components/BottomSheet/BottomSheet'; -import Button from './components/Button/Button'; -import DragHandleItem from './components/DragHandleItem/DragHandleItem'; -import DragHandleItemContainer from './components/DragHandleItemContainer/DragHandleItemContainer'; -import EditableItem from './components/EditableItem/EditableItem'; -import ExpenseList from './components/ExpenseList/ExpenseList'; -import FixedButton from './components/FixedButton/FixedButton'; -import Flex from './components/Flex/Flex'; -import Icon from './components/Icon/Icon'; -import IconButton from './components/IconButton/IconButton'; -import Input from './components/Input/Input'; -import LabelInput from './components/LabelInput/LabelInput'; -import ListButton from './components/ListButton/ListButton'; -import LabelGroupInput from './components/LabelGroupInput/LabelGroupInput'; -import Top from './components/Top/Top'; -import Tab from './components/Tabs/Tab'; -import Tabs from './components/Tabs/Tabs'; -import Text from './components/Text/Text'; -import TextButton from './components/TextButton/TextButton'; -import Title from './components/Title/Title'; -import TopNav from './components/TopNav/TopNav'; -import DepositCheck from './components/DepositCheck/DepositCheck'; -import DepositToggle from './components/DepositToggle/DepositToggle'; -import Amount from './components/Amount/Amount'; -import Dropdown from './components/Dropdown/Dropdown'; -import DropdownButton from './components/Dropdown/DropdownButton'; - -export { - BankSelect, - BottomSheet, - Button, - DragHandleItem, - DragHandleItemContainer, - EditableItem, - ExpenseList, - FixedButton, - Flex, - Icon, - IconButton, - Input, - LabelInput, - ListButton, - LabelGroupInput, - Top, - Tab, - Tabs, - Text, - TextButton, - Title, - TopNav, - MainLayout, - FunnelLayout, - ContentLayout, - HDesignProvider, - useTheme, - DepositCheck, - DepositToggle, - Amount, - Dropdown, - DropdownButton, -}; diff --git a/client/src/components/Design/layouts/FunnelLayout.tsx b/client/src/components/Design/layouts/FunnelLayout.tsx deleted file mode 100644 index 7dbe0c8e6..000000000 --- a/client/src/components/Design/layouts/FunnelLayout.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import {Flex} from '..'; - -const FunnelLayout = ({children}: React.PropsWithChildren) => { - return ( - - {children} - - ); -}; - -export default FunnelLayout; diff --git a/client/src/components/Design/token/zIndex.ts b/client/src/components/Design/token/zIndex.ts deleted file mode 100644 index 60ec5a6cd..000000000 --- a/client/src/components/Design/token/zIndex.ts +++ /dev/null @@ -1,39 +0,0 @@ -// Utils -const BASE = 0; -const ABOVE = 1; // use this for all values above the base -const BELOW = -1; // and this for all values below the base - -const NAV_BACKGROUND_COLOR = BASE + ABOVE; -const TAB_INDICATOR = BASE; -const TAB_TEXT = TAB_INDICATOR + ABOVE; -const FIXED_BUTTON = BASE + ABOVE; -const DEPOSIT_TOGGLE_INDICATOR_MOVING_ANIMATION = BASE + ABOVE; -const NUMBER_KEYBOARD_BOTTOM_SHEET = FIXED_BUTTON + ABOVE; -const BOTTOM_SHEET_DIMMED_LAYER = NUMBER_KEYBOARD_BOTTOM_SHEET + ABOVE; -const BOTTOM_SHEET_CONTAINER = BOTTOM_SHEET_DIMMED_LAYER + ABOVE; -const TOAST = BOTTOM_SHEET_CONTAINER + ABOVE; - -export const ZINDEX = { - bottomSheetDimmedLayer: BOTTOM_SHEET_DIMMED_LAYER, - bottomSheetContainer: BOTTOM_SHEET_CONTAINER, - numberKeyboardBottomSheet: NUMBER_KEYBOARD_BOTTOM_SHEET, - depositToggleMovingAnimation: DEPOSIT_TOGGLE_INDICATOR_MOVING_ANIMATION, - fixedButton: FIXED_BUTTON, - navBackgroundColor: NAV_BACKGROUND_COLOR, - tabIndicator: TAB_INDICATOR, - tabText: TAB_TEXT, - toast: TOAST, -} as const; - -type ZIndexKeys = - | 'bottomSheetDimmedLayer' - | 'bottomSheetContainer' - | 'numberKeyboardBottomSheet' - | 'depositToggleMovingAnimation' - | 'fixedButton' - | 'navBackgroundColor' - | 'tabText' - | 'tabIndicator' - | 'toast'; - -export type ZIndexTokens = Record; diff --git a/client/src/components/ExpenseDetailModal/ExpenseDetailModal.tsx b/client/src/components/ExpenseDetailModal/ExpenseDetailModal.tsx deleted file mode 100644 index ddc151387..000000000 --- a/client/src/components/ExpenseDetailModal/ExpenseDetailModal.tsx +++ /dev/null @@ -1,130 +0,0 @@ -// import type {BillAction} from 'types/serviceType'; - -// import validatePurchase from '@utils/validate/validatePurchase'; -// import useRequestGetSteps from '@hooks/queries/step/useRequestGetSteps'; -// import useMemberReportListInAction from '@hooks/useMemberReportListInAction/useMemberReportListInAction'; -// import useMemberReportInput from '@hooks/useMemberReportListInAction/useMemberReportInput'; - -// import usePutAndDeleteBill from '@hooks/usePutAndDeleteBill'; - -// import {BottomSheet, EditableItem, FixedButton, Flex, Text} from '@HDesign/index'; - -// type ExpenseDetailModalProps = { -// billAction: BillAction; -// isBottomSheetOpened: boolean; -// setIsBottomSheetOpened: React.Dispatch>; -// }; - -// const ExpenseDetailModal = ({billAction, isBottomSheetOpened, setIsBottomSheetOpened}: ExpenseDetailModalProps) => { -// const { -// inputPair, -// handleInputChange, -// // handleOnBlur, -// // errorMessage, -// // errorInfo, -// canSubmit, -// onDelete, -// onSubmit: putBillAction, -// } = usePutAndDeleteBill({title: billAction.name, price: String(billAction.price), index: 0}, validatePurchase, () => -// setIsBottomSheetOpened(false), -// ); - -// const { -// memberReportListInAction, -// addAdjustedMember, -// onSubmit: putMemberReportListInAction, -// getIsSamePriceStateAndServerState, -// getOnlyOneNotAdjustedRemainMemberIndex, -// isExistAdjustedPrice, -// } = useMemberReportListInAction(billAction.actionId, Number(inputPair.price), () => setIsBottomSheetOpened(false)); -// const { -// inputList, -// onChange, -// canEditList, -// canSubmit: isChangedMemberReportInput, -// } = useMemberReportInput({ -// data: memberReportListInAction, -// addAdjustedMember, -// totalPrice: Number(inputPair.price), -// getIsSamePriceStateAndServerState, -// getOnlyOneNotAdjustedRemainMemberIndex, -// }); - -// const {steps} = useRequestGetSteps(); - -// const actionMemberList = steps.filter(({actions}) => -// actions.find(({actionId}) => actionId === billAction.actionId), -// )[0].members; - -// return ( -// setIsBottomSheetOpened(false)}> -//
    setIsBottomSheetOpened(false)}> -//

    -// ์ง€์ถœ ๋‚ด์—ญ ์ƒ์„ธ -//

    -//
    -// -// ) => handleInputChange('title', event)} -// disabled -// /> -// -// ) => handleInputChange('price', event)} -// isFixed={isExistAdjustedPrice()} -// disabled -// /> -// ์› -// -// - -// -// -// {inputList.map(({name, price, isFixed}, index) => ( -// -// -// -// onChange(event, index)} -// isFixed={isFixed} -// textSize="smallBody" -// value={price} -// placeholder="0" -// type="number" -// disabled -// style={{textAlign: 'right'}} -// > -// ์› -// -// -// ))} -// -// -//
    -// -// ๋‹ซ๊ธฐ -// -//
    -//
    -// ); -// }; - -// export default ExpenseDetailModal; diff --git a/client/src/components/KakaoInitializer/KakaoInitializer.tsx b/client/src/components/KakaoInitializer/KakaoInitializer.tsx deleted file mode 100644 index d3ed82bab..000000000 --- a/client/src/components/KakaoInitializer/KakaoInitializer.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import {useEffect} from 'react'; - -const KakaoInitializer = ({children}: React.PropsWithChildren) => { - useEffect(() => { - if (!window.Kakao) return; - - if (!window.Kakao.isInitialized()) { - window.Kakao.init(process.env.KAKAO_JAVASCRIPT_KEY); - } - }, []); - - return children; -}; - -export default KakaoInitializer; diff --git a/client/src/components/MemberReportList/MemberReportList.tsx b/client/src/components/MemberReportList/MemberReportList.tsx new file mode 100644 index 000000000..1004540fa --- /dev/null +++ b/client/src/components/MemberReportList/MemberReportList.tsx @@ -0,0 +1,22 @@ +import {ExpenseList, Flex, Input} from 'haengdong-design'; +import React, {useState} from 'react'; + +import useSearchMemberReportList from '@hooks/useSearchMemberReportList/useSearchMemberReportList'; + +const MemberReportList = () => { + const [name, setName] = useState(''); + const {memberReportSearchList} = useSearchMemberReportList({name}); + + const changeName = ({target}: React.ChangeEvent) => { + setName(target.value); + }; + + return ( + + + + + ); +}; + +export default MemberReportList; diff --git a/client/src/components/Modal/BankSelectModal/BankSelectModal.tsx b/client/src/components/Modal/BankSelectModal/BankSelectModal.tsx deleted file mode 100644 index 02082fd75..000000000 --- a/client/src/components/Modal/BankSelectModal/BankSelectModal.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import {BankSelect, BottomSheet, Text} from '@HDesign/index'; - -import {bottomSheetHeaderStyle, bottomSheetStyle, inputContainerStyle} from './BankSelectModal.style'; - -type BankSelectProps = { - isBottomSheetOpened: boolean; - setIsBottomSheetOpened: React.Dispatch>; - selectBank: (name: string) => void; -}; - -const BankSelectModal = ({isBottomSheetOpened, setIsBottomSheetOpened, selectBank}: BankSelectProps) => { - const selectBankAndClose = (name: string) => { - selectBank(name); - setIsBottomSheetOpened(false); - }; - - return ( - setIsBottomSheetOpened(false)}> -
    -

    - ์€ํ–‰์„ ์„ ํƒํ•ด์ฃผ์„ธ์š” -

    -
    - -
    -
    -
    - ); -}; - -export default BankSelectModal; diff --git a/client/src/components/Modal/ExpenseDetailModal/ExpenseDetailModal.tsx b/client/src/components/Modal/ExpenseDetailModal/ExpenseDetailModal.tsx new file mode 100644 index 000000000..645acb468 --- /dev/null +++ b/client/src/components/Modal/ExpenseDetailModal/ExpenseDetailModal.tsx @@ -0,0 +1,142 @@ +import type {BillAction} from 'types/serviceType'; + +import {BottomSheet, EditableItem, FixedButton, Flex, Text} from 'haengdong-design'; + +import validatePurchase from '@utils/validate/validatePurchase'; +import useRequestGetStepList from '@hooks/queries/useRequestGetStepList'; +import useMemberReportListInAction from '@hooks/useMemberReportListInAction/useMemberReportListInAction'; +import useMemberReportInput from '@hooks/useMemberReportListInAction/useMemberReportInput'; + +import usePutAndDeleteBillAction from '@hooks/usePutAndDeleteBillAction'; + +import { + bottomSheetHeaderStyle, + bottomSheetStyle, + inputContainerStyle, +} from '../SetActionModal/PutAndDeleteBillActionModal/PutAndDeltetBillActionModal.style'; + +type PutAndDeleteBillActionModalProps = { + billAction: BillAction; + isBottomSheetOpened: boolean; + setIsBottomSheetOpened: React.Dispatch>; +}; + +const ExpenseDetailModal = ({ + billAction, + isBottomSheetOpened, + setIsBottomSheetOpened, +}: PutAndDeleteBillActionModalProps) => { + const { + inputPair, + handleInputChange, + // handleOnBlur, + // errorMessage, + // errorInfo, + canSubmit, + onDelete, + onSubmit: putBillAction, + } = usePutAndDeleteBillAction( + {title: billAction.name, price: String(billAction.price), index: 0}, + validatePurchase, + () => setIsBottomSheetOpened(false), + ); + + const { + memberReportListInAction, + addAdjustedMember, + onSubmit: putMemberReportListInAction, + getIsSamePriceStateAndServerState, + getOnlyOneNotAdjustedRemainMemberIndex, + isExistAdjustedPrice, + } = useMemberReportListInAction(billAction.actionId, Number(inputPair.price), () => setIsBottomSheetOpened(false)); + const { + inputList, + onChange, + canEditList, + canSubmit: isChangedMemberReportInput, + } = useMemberReportInput({ + data: memberReportListInAction, + addAdjustedMember, + totalPrice: Number(inputPair.price), + getIsSamePriceStateAndServerState, + getOnlyOneNotAdjustedRemainMemberIndex, + }); + + const {data: stepListData = []} = useRequestGetStepList(); + + const actionMemberList = stepListData.filter(({actions}) => + actions.find(({actionId}) => actionId === billAction.actionId), + )[0].members; + + return ( + setIsBottomSheetOpened(false)}> +
    setIsBottomSheetOpened(false)}> +

    + ์ง€์ถœ ๋‚ด์—ญ ์ƒ์„ธ +

    +
    + + ) => handleInputChange('title', event)} + disabled + /> + + ) => handleInputChange('price', event)} + isFixed={isExistAdjustedPrice()} + disabled + /> + ์› + + + + + + {inputList.map(({name, price, isFixed}, index) => ( + + + + onChange(event, index)} + isFixed={isFixed} + textSize="smallBody" + value={price} + placeholder="0" + type="number" + disabled + style={{textAlign: 'right'}} + > + ์› + + + ))} + + +
    + + ๋‹ซ๊ธฐ + +
    +
    + ); +}; + +export default ExpenseDetailModal; diff --git a/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.style.ts b/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.style.ts new file mode 100644 index 000000000..4bbefdba9 --- /dev/null +++ b/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.style.ts @@ -0,0 +1,10 @@ +import {css} from '@emotion/react'; + +export const bottomSheetStyle = css({ + display: 'flex', + flexDirection: 'column', + gap: '1.5rem', + width: '100%', + height: '100%', + padding: '0 1.5rem', +}); diff --git a/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.tsx b/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.tsx new file mode 100644 index 000000000..e3579ab6b --- /dev/null +++ b/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.tsx @@ -0,0 +1,53 @@ +import type {MemberReport} from 'types/serviceType'; + +import {BottomSheet, FixedButton, Flex, Text} from 'haengdong-design'; + +import {bottomSheetStyle} from './MemberListInBillStep.style'; + +type MemberListInBillStepProps = { + stepName: string; + memberList: MemberReport[]; + isOpenBottomSheet: boolean; + setIsOpenBottomSheet: React.Dispatch>; +}; + +const MemberListInBillStep = ({ + stepName, + memberList, + isOpenBottomSheet, + setIsOpenBottomSheet, +}: MemberListInBillStepProps) => { + const closeModal = () => setIsOpenBottomSheet(false); + + return ( + +
    + + {`${stepName} ์ฐธ์„์ž`} + {`์ด ${memberList.length}๋ช…`} + + +
      + {memberList.map(member => ( +
    • + + + {member.name} + + + {`${member.price.toLocaleString('ko-kr')} ์›`} + + +
    • + ))} +
    +
    +
    + + ๋‹ซ๊ธฐ + +
    + ); +}; + +export default MemberListInBillStep; diff --git a/client/src/components/Modal/MemberListInBillStep/index.ts b/client/src/components/Modal/MemberListInBillStep/index.ts new file mode 100644 index 000000000..137df8c87 --- /dev/null +++ b/client/src/components/Modal/MemberListInBillStep/index.ts @@ -0,0 +1 @@ +export {default as MemberListInBillStep} from './MemberListInBillStep'; diff --git a/client/src/components/Modal/ModalBasedOnMemberCount/ModalBasedOnMemberCount.tsx b/client/src/components/Modal/ModalBasedOnMemberCount/ModalBasedOnMemberCount.tsx new file mode 100644 index 000000000..51e33589b --- /dev/null +++ b/client/src/components/Modal/ModalBasedOnMemberCount/ModalBasedOnMemberCount.tsx @@ -0,0 +1,39 @@ +import {SetAllMemberListModal, SetInitialMemberListModal, SetActionListModal} from '@components/Modal/index'; + +interface ModalBasedOnMemberCountProps { + allMemberList: string[]; + isOpenBottomSheet: boolean; + isOpenAllMemberListButton: boolean; + setIsOpenBottomSheet: React.Dispatch>; + setIsOpenAllMemberListButton: React.Dispatch>; +} + +const ModalBasedOnMemberCount = ({ + allMemberList, + isOpenBottomSheet, + isOpenAllMemberListButton, + setIsOpenBottomSheet, + setIsOpenAllMemberListButton, +}: ModalBasedOnMemberCountProps) => { + if (isOpenAllMemberListButton) { + return ( + + ); + } + switch (allMemberList.length) { + case 0: + return ( + + ); + + default: + return ; + } +}; + +export default ModalBasedOnMemberCount; diff --git a/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.style.ts b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.style.ts new file mode 100644 index 000000000..7fad2e001 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.style.ts @@ -0,0 +1,23 @@ +import {css} from '@emotion/react'; + +const container = css({ + display: 'flex', + flexDirection: 'column', + gap: '1.5rem', + height: '100%', +}); + +const inputGroup = css({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + overflow: 'auto', + paddingBottom: '14rem', +}); + +const addMemberActionListModalContentStyle = { + container, + inputGroup, +}; + +export default addMemberActionListModalContentStyle; diff --git a/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.tsx b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.tsx new file mode 100644 index 000000000..ad6e63f28 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.tsx @@ -0,0 +1,50 @@ +import type {MemberType} from 'types/serviceType'; + +import {FixedButton, LabelGroupInput} from 'haengdong-design'; + +import validateMemberName from '@utils/validate/validateMemberName'; +import useRequestPostMemberList from '@hooks/queries/useRequestPostMemberList'; + +import useDynamicInput from '@hooks/useDynamicInput'; + +import style from './AddMemberActionListModalContent.style'; +import InMember from './InMember'; +import OutMember from './OutMember'; + +interface AddMemberActionListModalContentProps { + inOutAction: MemberType; + setIsOpenBottomSheet: React.Dispatch>; +} + +const AddMemberActionListModalContent = ({inOutAction, setIsOpenBottomSheet}: AddMemberActionListModalContentProps) => { + const dynamicProps = useDynamicInput(validateMemberName); + const {inputList, getFilledInputList, errorMessage, canSubmit, resetInputValue} = dynamicProps; + + const {mutate: postMemberList} = useRequestPostMemberList(); + + const handleUpdateMemberListSubmit = () => { + postMemberList({memberNameList: getFilledInputList().map(({value}) => value), type: inOutAction}); + setIsOpenBottomSheet(false); + }; + + return ( +
    +
    + + {inOutAction === 'IN' ? : } + +
    + { + handleUpdateMemberListSubmit(); + resetInputValue(); + }} + /> +
    + ); +}; + +export default AddMemberActionListModalContent; diff --git a/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/InMember.tsx b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/InMember.tsx new file mode 100644 index 000000000..5f9f9a2e0 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/InMember.tsx @@ -0,0 +1,35 @@ +import {LabelGroupInput} from 'haengdong-design'; + +import {ReturnUseDynamicInput} from '@hooks/useDynamicInput'; + +interface InMemberProps { + dynamicProps: ReturnUseDynamicInput; +} + +const InMember = ({dynamicProps}: InMemberProps) => { + const { + inputList, + inputRefList, + handleInputChange, + deleteEmptyInputElementOnBlur, + focusNextInputOnEnter, + errorIndexList, + } = dynamicProps; + return inputList.map(({value, index}) => ( + (inputRefList.current[index] = el)} + isError={errorIndexList.includes(index)} + onChange={e => handleInputChange(index, e)} + onBlur={() => deleteEmptyInputElementOnBlur()} + onKeyDown={e => focusNextInputOnEnter(e, index)} + placeholder="์ด๋ฆ„" + autoFocus={inputList.length === 1 && index === 0} + /> + )); +}; + +export default InMember; diff --git a/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/OutMember.tsx b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/OutMember.tsx new file mode 100644 index 000000000..9294b18ae --- /dev/null +++ b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/OutMember.tsx @@ -0,0 +1,52 @@ +import {LabelGroupInput, Search} from 'haengdong-design'; + +import {ReturnUseDynamicInput} from '@hooks/useDynamicInput'; +import useSearchInMemberList from '@hooks/useSearchInMemberList'; + +interface OutMemberProps { + dynamicProps: ReturnUseDynamicInput; +} + +const OutMember = ({dynamicProps}: OutMemberProps) => { + const { + inputList, + inputRefList, + errorIndexList, + deleteEmptyInputElementOnBlur, + focusNextInputOnEnter, + handleInputChange, + handleChange, + } = dynamicProps; + const {currentInputIndex, filteredInMemberList, handleCurrentInputIndex, searchCurrentInMember, chooseMember} = + useSearchInMemberList(handleChange); + + const validationAndSearchOnChange = (inputIndex: number, event: React.ChangeEvent) => { + handleCurrentInputIndex(inputIndex); + handleInputChange(inputIndex, event); + searchCurrentInMember(event); + }; + + return inputList.map(({value, index}) => ( + chooseMember(currentInputIndex, term)} + > + (inputRefList.current[index] = el)} + isError={errorIndexList.includes(index)} + onChange={e => validationAndSearchOnChange(index, e)} + onBlur={() => deleteEmptyInputElementOnBlur()} + onKeyDown={e => focusNextInputOnEnter(e, index)} + placeholder="์ด๋ฆ„" + autoFocus={inputList.length === 1 && index === 0} + /> + + )); +}; + +export default OutMember; diff --git a/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/index.ts b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/index.ts new file mode 100644 index 000000000..6519283f4 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/index.ts @@ -0,0 +1 @@ +export {default as AddMemberActionListModalContent} from './AddMemberActionListModalContent'; diff --git a/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.style.ts b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.style.ts new file mode 100644 index 000000000..7be2f2141 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.style.ts @@ -0,0 +1,27 @@ +import {css} from '@emotion/react'; + +export const bottomSheetStyle = css({ + display: 'flex', + flexDirection: 'column', + gap: '1.5rem', + width: '100%', + height: '100%', + padding: '0 1rem', +}); + +export const bottomSheetHeaderStyle = css({ + display: 'flex', + justifyContent: 'space-between', + alignContent: 'center', + + width: '100%', + padding: '0 0.5rem', +}); + +export const inputGroupStyle = css({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + overflow: 'auto', + paddingBottom: '11rem', +}); diff --git a/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.tsx b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.tsx new file mode 100644 index 000000000..04242fad1 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.tsx @@ -0,0 +1,88 @@ +import type {MemberAction, MemberType} from 'types/serviceType'; + +import {BottomSheet, Flex, Input, Text, IconButton, FixedButton, Icon} from 'haengdong-design'; + +import useDeleteMemberAction from '@hooks/useDeleteMemberAction/useDeleteMemberAction'; +import {useToast} from '@hooks/useToast/useToast'; + +import {bottomSheetHeaderStyle, bottomSheetStyle, inputGroupStyle} from './DeleteMemberActionModal.style'; + +type DeleteMemberActionModalProps = { + memberActionType: MemberType; + memberActionList: MemberAction[]; + isBottomSheetOpened: boolean; + setIsBottomSheetOpened: React.Dispatch>; +}; + +const DeleteMemberActionModal = ({ + memberActionType, + memberActionList, + isBottomSheetOpened, + setIsBottomSheetOpened, +}: DeleteMemberActionModalProps) => { + const {showToast} = useToast(); + + const showToastAlreadyExistMemberAction = () => { + showToast({ + isClickToClose: true, + showingTime: 3000, + message: '์ด๋ฏธ ์‚ญ์ œ๋œ ์ธ์›์ž…๋‹ˆ๋‹ค.', + type: 'error', + bottom: '160px', + }); + }; + + const showToastExistSameMemberFromAfterStep = (name: string) => { + showToast({ + isClickToClose: true, + showingTime: 3000, + message: `์ดํ›„์˜ ${name}๊ฐ€ ์‚ฌ๋ผ์ ธ์š”`, + type: 'error', + position: 'top', + top: '30px', + style: { + zIndex: 9000, + }, + }); + }; + + const {aliveActionList, deleteMemberActionList, addDeleteMemberAction} = useDeleteMemberAction({ + memberActionList, + setIsBottomSheetOpened, + showToastAlreadyExistMemberAction, + showToastExistSameMemberFromAfterStep, + }); + + return ( + setIsBottomSheetOpened(false)}> +
    +
    + {memberActionType === 'IN' ? '๋“ค์–ด์˜จ' : '๋‚˜๊ฐ„'} ์ธ์› ์ˆ˜์ •ํ•˜๊ธฐ + {`${aliveActionList.length}๋ช…`} +
    +
      + {aliveActionList.map(member => ( +
    • + +
      + +
      + addDeleteMemberAction(member)}> + + +
      +
    • + ))} +
    + +
    +
    + ); +}; + +export default DeleteMemberActionModal; diff --git a/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/index.ts b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/index.ts new file mode 100644 index 000000000..2a6b52b45 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/index.ts @@ -0,0 +1 @@ +export {default as DeleteMemberActionModal} from './DeleteMemberActionModal'; diff --git a/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeleteBillActionModal.tsx b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeleteBillActionModal.tsx new file mode 100644 index 000000000..5f7d4501e --- /dev/null +++ b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeleteBillActionModal.tsx @@ -0,0 +1,149 @@ +import type {BillAction} from 'types/serviceType'; + +import {BottomSheet, EditableItem, FixedButton, Flex, Text} from 'haengdong-design'; + +import validatePurchase from '@utils/validate/validatePurchase'; +import useRequestGetStepList from '@hooks/queries/useRequestGetStepList'; +import useMemberReportListInAction from '@hooks/useMemberReportListInAction/useMemberReportListInAction'; +import useMemberReportInput from '@hooks/useMemberReportListInAction/useMemberReportInput'; + +import usePutAndDeleteBillAction from '@hooks/usePutAndDeleteBillAction'; + +import {bottomSheetHeaderStyle, bottomSheetStyle, inputContainerStyle} from './PutAndDeltetBillActionModal.style'; + +type PutAndDeleteBillActionModalProps = { + billAction: BillAction; + isBottomSheetOpened: boolean; + setIsBottomSheetOpened: React.Dispatch>; +}; + +const PutAndDeleteBillActionModal = ({ + billAction, + isBottomSheetOpened, + setIsBottomSheetOpened, +}: PutAndDeleteBillActionModalProps) => { + const { + inputPair, + handleInputChange, + // handleOnBlur, + // errorMessage, + // errorInfo, + canSubmit, + onDelete, + onSubmit: putBillAction, + } = usePutAndDeleteBillAction( + {title: billAction.name, price: String(billAction.price), index: 0}, + validatePurchase, + () => setIsBottomSheetOpened(false), + ); + + const { + memberReportListInAction, + addAdjustedMember, + onSubmit: putMemberReportListInAction, + getIsSamePriceStateAndServerState, + getOnlyOneNotAdjustedRemainMemberIndex, + isExistAdjustedPrice, + } = useMemberReportListInAction(billAction.actionId, Number(inputPair.price), () => setIsBottomSheetOpened(false)); + const { + inputList, + onChange, + canEditList, + canSubmit: isChangedMemberReportInput, + } = useMemberReportInput({ + data: memberReportListInAction, + addAdjustedMember, + totalPrice: Number(inputPair.price), + getIsSamePriceStateAndServerState, + getOnlyOneNotAdjustedRemainMemberIndex, + }); + + const {data: stepListData = []} = useRequestGetStepList(); + + const actionMemberList = stepListData.filter(({actions}) => + actions.find(({actionId}) => actionId === billAction.actionId), + )[0].members; + + return ( + setIsBottomSheetOpened(false)}> +
    { + event.preventDefault(); + + if (canSubmit) await putBillAction(event, inputPair, billAction.actionId); + if (isChangedMemberReportInput) putMemberReportListInAction(); + }} + > +

    + ์ง€์ถœ ๋‚ด์—ญ ์ˆ˜์ •ํ•˜๊ธฐ +

    +
    + + ) => handleInputChange('title', event)} + /> + + ) => handleInputChange('price', event)} + isFixed={isExistAdjustedPrice()} + /> + ์› + + + + + + {inputList.map(({name, price, isFixed}, index) => ( + + + + onChange(event, index)} + isFixed={isFixed} + textSize="smallBody" + value={price} + placeholder="0" + type="number" + readOnly={!canEditList[index]} + style={{textAlign: 'right'}} + > + ์› + + + ))} + + +
    + onDelete(billAction.actionId)} + > + ์ˆ˜์ • ์™„๋ฃŒ + +
    +
    + ); +}; + +export default PutAndDeleteBillActionModal; diff --git a/client/src/components/Modal/BankSelectModal/BankSelectModal.style.ts b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeltetBillActionModal.style.ts similarity index 95% rename from client/src/components/Modal/BankSelectModal/BankSelectModal.style.ts rename to client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeltetBillActionModal.style.ts index cec3609de..f58f43425 100644 --- a/client/src/components/Modal/BankSelectModal/BankSelectModal.style.ts +++ b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeltetBillActionModal.style.ts @@ -24,5 +24,5 @@ export const inputContainerStyle = css({ flexDirection: 'column', gap: '1.5rem', overflow: 'auto', - paddingBottom: '4rem', + paddingBottom: '14rem', }); diff --git a/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/index.ts b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/index.ts new file mode 100644 index 000000000..c7cbcfcb6 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/index.ts @@ -0,0 +1 @@ +export {default as PutAndDeleteBillActionModal} from './PutAndDeleteBillActionModal'; diff --git a/client/src/components/Modal/SetActionModal/SetActionListModal.style.ts b/client/src/components/Modal/SetActionModal/SetActionListModal.style.ts new file mode 100644 index 000000000..ca6703309 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/SetActionListModal.style.ts @@ -0,0 +1,20 @@ +import {css} from '@emotion/react'; + +export const container = css({ + display: 'flex', + flexDirection: 'column', + width: '100%', + height: '100%', + padding: '0 1.5rem', + gap: '1.5rem', +}); + +export const switchContainer = css({ + display: 'flex', + width: '100%', + justifyContent: 'space-between', +}); + +const setActionListModalStyle = {container, switchContainer}; + +export default setActionListModalStyle; diff --git a/client/src/components/Modal/SetActionModal/SetActionListModal.tsx b/client/src/components/Modal/SetActionModal/SetActionListModal.tsx new file mode 100644 index 000000000..862bd91e3 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/SetActionListModal.tsx @@ -0,0 +1,42 @@ +import type {InOutType} from 'types/serviceType'; + +import {useState} from 'react'; +import {BottomSheet, Switch, Text} from 'haengdong-design'; + +import {AddMemberActionListModalContent} from './AddMemberActionListModalContent'; +import style from './SetActionListModal.style'; + +export type ActionType = '์ง€์ถœ' | '์ธ์›'; + +interface SetActionModalContentProps { + isOpenBottomSheet: boolean; + setIsOpenBottomSheet: React.Dispatch>; +} + +const SetActionListModal = ({isOpenBottomSheet, setIsOpenBottomSheet}: SetActionModalContentProps) => { + const [inOutAction, setInOutAction] = useState('ํƒˆ์ฃผ'); + + const handleParticipantTypeChange = (value: string) => { + setInOutAction(value as InOutType); + }; + + return ( + setIsOpenBottomSheet(false)}> +
    +
    + + ์ธ์› ๋ณ€๋™ + + +
    + + +
    +
    + ); +}; + +export default SetActionListModal; diff --git a/client/src/components/Modal/SetActionModal/index.ts b/client/src/components/Modal/SetActionModal/index.ts new file mode 100644 index 000000000..f689cb596 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/index.ts @@ -0,0 +1 @@ +export {default as SetActionListModal} from './SetActionListModal'; diff --git a/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.style.ts b/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.style.ts new file mode 100644 index 000000000..f54166c08 --- /dev/null +++ b/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.style.ts @@ -0,0 +1,36 @@ +import {css} from '@emotion/react'; + +export const allMemberListModalStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + width: '100%', + height: '100%', + }); + +export const allMemberListModalTitleStyle = () => + css({ + display: 'flex', + justifyContent: 'space-between', + width: '100%', + padding: '0 1.5rem', + }); + +export const allMemberListModalLabelGroupInputStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + padding: '0 1rem', + paddingBottom: '10rem', + + overflow: 'auto', + }); + +export const InputAndDeleteButtonContainer = () => + css({ + display: 'flex', + alignItems: 'center', + width: '100%', + gap: '1rem', + }); diff --git a/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.tsx b/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.tsx new file mode 100644 index 000000000..58e86b917 --- /dev/null +++ b/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.tsx @@ -0,0 +1,80 @@ +import {BottomSheet, Text, LabelGroupInput, FixedButton, IconButton, Icon} from 'haengdong-design'; + +import validateMemberName from '@utils/validate/validateMemberName'; + +import useSetAllMemberList from '@hooks/useSetAllMemberList'; + +import { + allMemberListModalLabelGroupInputStyle, + allMemberListModalStyle, + allMemberListModalTitleStyle, + InputAndDeleteButtonContainer, +} from './SetAllMemberListModal.style'; + +interface SetAllMemberListModalProps { + isOpenBottomSheet: boolean; + allMemberList: string[]; + setIsOpenBottomSheet: React.Dispatch>; + setIsOpenAllMemberListButton: React.Dispatch>; +} + +const SetAllMemberListModal = ({ + isOpenBottomSheet, + allMemberList, + setIsOpenBottomSheet, + setIsOpenAllMemberListButton, +}: SetAllMemberListModalProps) => { + const handleCloseAllMemberListModal = () => { + setIsOpenAllMemberListButton(prev => !prev); + setIsOpenBottomSheet(false); + }; + + const { + editedAllMemberList, + canSubmit, + errorMessage, + errorIndexList, + handleNameChange, + handleClickDeleteButton, + handlePutAllMemberList, + } = useSetAllMemberList({ + validateFunc: validateMemberName, + allMemberList, + handleCloseAllMemberListModal, + }); + + return ( + +
    +
    + ์ „์ฒด ์ฐธ์—ฌ์ž ์ˆ˜์ •ํ•˜๊ธฐ + + ์ด {allMemberList.length}๋ช… + +
    +
    + + {editedAllMemberList.map((member, index) => ( +
    +
    + handleNameChange(index, e)} + /> +
    + handleClickDeleteButton(index)}> + + +
    + ))} +
    +
    + +
    +
    + ); +}; + +export default SetAllMemberListModal; diff --git a/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.style.ts b/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.style.ts new file mode 100644 index 000000000..ed835682c --- /dev/null +++ b/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.style.ts @@ -0,0 +1,20 @@ +import {css} from '@emotion/react'; + +export const setInitialMemberListModalStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '1.5rem', + width: '100%', + height: '100%', + padding: '0 1.5rem', + }); + +export const setInitialMemberListModalInputGroupStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + overflow: 'auto', + paddingBottom: '11rem', + }); diff --git a/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.tsx b/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.tsx new file mode 100644 index 000000000..f73f2616d --- /dev/null +++ b/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.tsx @@ -0,0 +1,66 @@ +import {Text, BottomSheet, FixedButton, LabelGroupInput} from 'haengdong-design'; + +import validateMemberName from '@utils/validate/validateMemberName'; +import useRequestPostMemberList from '@hooks/queries/useRequestPostMemberList'; + +import useDynamicInput from '@hooks/useDynamicInput'; + +import { + setInitialMemberListModalInputGroupStyle, + setInitialMemberListModalStyle, +} from './SetInitialMemberListModal.style'; + +interface SetInitialMemberListProps { + isOpenBottomSheet: boolean; + setIsOpenBottomSheet: React.Dispatch>; +} + +const SetInitialMemberListModal = ({isOpenBottomSheet, setIsOpenBottomSheet}: SetInitialMemberListProps) => { + const { + inputList, + inputRefList, + handleInputChange, + deleteEmptyInputElementOnBlur, + getFilledInputList, + errorMessage, + canSubmit, + errorIndexList, + focusNextInputOnEnter, + } = useDynamicInput(validateMemberName); + const {mutate: postMemberList} = useRequestPostMemberList(); + + const handleSubmit = () => { + postMemberList({memberNameList: getFilledInputList().map(({value}) => value), type: 'IN'}); + setIsOpenBottomSheet(false); + }; + + return ( + setIsOpenBottomSheet(false)}> +
    + ์‹œ์ž‘ ์ธ์› ์ถ”๊ฐ€ํ•˜๊ธฐ +
    + + {inputList.map(({value, index}) => ( + (inputRefList.current[index] = el)} + onChange={e => handleInputChange(index, e)} + onBlur={() => deleteEmptyInputElementOnBlur()} + onKeyDown={e => focusNextInputOnEnter(e, index)} + autoFocus={inputList.length === 1 && index === 0} + /> + ))} + +
    +
    + +
    + ); +}; + +export default SetInitialMemberListModal; diff --git a/client/src/components/Modal/SetInitialMemberListModal/index.ts b/client/src/components/Modal/SetInitialMemberListModal/index.ts new file mode 100644 index 000000000..18098e4f6 --- /dev/null +++ b/client/src/components/Modal/SetInitialMemberListModal/index.ts @@ -0,0 +1 @@ +export {default as SetInitialMemberListModal} from './SetInitialMemberListModal'; diff --git a/client/src/components/Modal/index.ts b/client/src/components/Modal/index.ts new file mode 100644 index 000000000..180063b03 --- /dev/null +++ b/client/src/components/Modal/index.ts @@ -0,0 +1,4 @@ +export {default as SetActionListModal} from './SetActionModal/SetActionListModal'; +export {default as SetInitialMemberListModal} from './SetInitialMemberListModal/SetInitialMemberListModal'; +export {default as SetAllMemberListModal} from './SetAllMemberListModal/SetAllMemberListModal'; +export {default as ModalBasedOnMemberCount} from './ModalBasedOnMemberCount/ModalBasedOnMemberCount'; diff --git a/client/src/components/QueryClientBoundary/QueryClientBoundary.tsx b/client/src/components/QueryClientBoundary/QueryClientBoundary.tsx index 0ff8bf202..aeec24c3a 100644 --- a/client/src/components/QueryClientBoundary/QueryClientBoundary.tsx +++ b/client/src/components/QueryClientBoundary/QueryClientBoundary.tsx @@ -1,24 +1,13 @@ import {MutationCache, QueryCache, QueryClient, QueryClientProvider} from '@tanstack/react-query'; -import {RequestGetError} from '@errors/RequestGetError'; - import {useAppErrorStore} from '@store/appErrorStore'; const QueryClientBoundary = ({children}: React.PropsWithChildren) => { const {updateAppError} = useAppErrorStore(); const queryClient = new QueryClient({ - // errorBoundary๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด true๋กœ ํ•ด์ค˜์•ผํ•จ. - defaultOptions: { - queries: { - throwOnError: true, - }, - }, queryCache: new QueryCache({ onError: (error: Error) => { - // errorBoundary๋กœ ์ฒ˜๋ฆฌํ•ด์•ผํ•˜๋Š” ์—๋Ÿฌ์ธ ๊ฒฝ์šฐ updateAppError๋ฅผ ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์–ผ๋ฆฌ๋ฆฌํ„ด - if (error instanceof RequestGetError && error.errorHandlingStrategy === 'errorBoundary') return; - updateAppError(error); }, }), diff --git a/client/src/components/Reports/Reports.tsx b/client/src/components/Reports/Reports.tsx deleted file mode 100644 index 74b59dbb9..000000000 --- a/client/src/components/Reports/Reports.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import BillEmptyFallback from '@pages/EventPage/EventPageFallback/BillEmptyFallback'; - -import useReportsPage from '@hooks/useReportsPage'; - -import {ExpenseList, Flex} from '@HDesign/index'; - -const Reports = () => { - const {isEmpty, expenseListProp, memberName, changeName} = useReportsPage(); - - if (isEmpty) { - return ; - } - - return ( - - - - ); -}; - -export default Reports; diff --git a/client/src/components/ShareEventButton/ShareEventButton.tsx b/client/src/components/ShareEventButton/ShareEventButton.tsx deleted file mode 100644 index f8a968003..000000000 --- a/client/src/components/ShareEventButton/ShareEventButton.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import CopyToClipboard from 'react-copy-to-clipboard'; -import {useNavigate} from 'react-router-dom'; - -import toast from '@hooks/useToast/toast'; -import {Event} from 'types/serviceType'; - -import useShareEvent from '@hooks/useShareEvent'; - -import {Button} from '@components/Design'; - -import {isMobileDevice} from '@utils/detectDevice'; -import getDeletedLastPath from '@utils/getDeletedLastPath'; - -type ShareEventButtonProps = { - eventOutline: Event; -}; - -const ShareEventButton = ({eventOutline}: ShareEventButtonProps) => { - const {eventName, bankName, accountNumber} = eventOutline; - const navigate = useNavigate(); - - const isMobile = isMobileDevice(); - const {shareText, onShareButtonClick} = useShareEvent(eventName, isMobile); - - const induceBankInfoBeforeShare = () => { - if (bankName === '' || accountNumber === '') { - toast.confirm('์ž ๊น! ์ •์‚ฐ์„ ์ดˆ๋Œ€ํ•˜๊ธฐ ์ „์—\n๊ณ„์ขŒ๋ฅผ ๋“ฑ๋กํ•ด์ฃผ์„ธ์š”', { - showingTime: 3000, - position: 'bottom', - }); - - const navigatePath = `${getDeletedLastPath(location.pathname)}/admin/edit`; - - navigate(navigatePath); - return; - } - - onShareButtonClick(); - }; - - return isMobile ? ( - - ) : ( - - toast.confirm('๋งํฌ๊ฐ€ ๋ณต์‚ฌ๋˜์—ˆ์–ด์š” :) \n์ฐธ์—ฌ์ž๋“ค์—๊ฒŒ ๋งํฌ๋ฅผ ๊ณต์œ ํ•ด ์ฃผ์„ธ์š”!', { - showingTime: 3000, - position: 'bottom', - }) - } - > - - - ); -}; - -export default ShareEventButton; diff --git a/client/src/components/ShareEventButton/index.ts b/client/src/components/ShareEventButton/index.ts deleted file mode 100644 index 27b5883aa..000000000 --- a/client/src/components/ShareEventButton/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default as ShareEventButton} from './ShareEventButton'; diff --git a/client/src/components/StepList/BillStepItem.tsx b/client/src/components/StepList/BillStepItem.tsx new file mode 100644 index 000000000..7fed9ef5c --- /dev/null +++ b/client/src/components/StepList/BillStepItem.tsx @@ -0,0 +1,138 @@ +import {DragHandleItem, DragHandleItemContainer, EditableItem, Flex, Text} from 'haengdong-design'; +import {Fragment, useState} from 'react'; +import {useOutletContext} from 'react-router-dom'; + +import {BillStep, MemberReport} from 'types/serviceType'; +import {PutAndDeleteBillActionModal} from '@components/Modal/SetActionModal/PutAndDeleteBillActionModal'; +import {MemberListInBillStep} from '@components/Modal/MemberListInBillStep'; +import {EventPageContextProps} from '@pages/EventPage/EventPageLayout'; +import ExpenseDetailModal from '@components/Modal/ExpenseDetailModal/ExpenseDetailModal'; + +import useSetBillInput from '@hooks/useSetBillInput'; + +interface BillStepItemProps { + step: BillStep; + isOpenBottomSheet: boolean; + setIsOpenBottomSheet: React.Dispatch>; + isAddEditableItem: boolean; + setIsAddEditableItem: React.Dispatch>; + isLastBillItem: boolean; + index: number; +} + +const BillStepItem: React.FC = ({ + step, + isOpenBottomSheet, + setIsOpenBottomSheet, + isAddEditableItem, + setIsAddEditableItem, + isLastBillItem, + index, +}) => { + const {isAdmin} = useOutletContext(); + const {handleBlurBillRequest, handleChangeBillInput, billInput} = useSetBillInput({setIsAddEditableItem}); + + const [clickedIndex, setClickedIndex] = useState(-1); + const [isOpenMemberListInBillStep, setIsOpenMemberListInBillStep] = useState(false); + + const totalPrice = step.actions && step.type === 'BILL' ? step.actions.reduce((acc, cur) => acc + cur.price, 0) : 0; + + const handleDragHandleItemClick = (index: number) => { + setClickedIndex(index); + setIsOpenBottomSheet(true); + }; + + const memberList: MemberReport[] = step.members.map(member => ({ + name: member, + price: totalPrice / step.members.length, + })); + + const handleTopRightTextClick = () => { + setIsOpenMemberListInBillStep(true); + }; + + return ( + <> + + {step.actions && + step.type === 'BILL' && + step.actions.map((action, index) => ( + + handleDragHandleItemClick(index)} + isFixed={action.isFixed} + /> + + {isOpenBottomSheet && clickedIndex === index && isAdmin && ( + + )} + {isOpenBottomSheet && clickedIndex === index && !isAdmin && ( + + )} + + ))} + + {isAddEditableItem && isLastBillItem && ( + { + if (e.key === 'Enter') { + handleBlurBillRequest(); + } + }} + > + handleChangeBillInput('title', e)} + autoFocus + > + + handleChangeBillInput('price', e)} + style={{textAlign: 'right'}} + > + ์› + + + )} + + + + ); +}; + +export default BillStepItem; diff --git a/client/src/components/StepList/MemberStepItem.tsx b/client/src/components/StepList/MemberStepItem.tsx new file mode 100644 index 000000000..ed3f5bfe7 --- /dev/null +++ b/client/src/components/StepList/MemberStepItem.tsx @@ -0,0 +1,38 @@ +import type {MemberStep} from 'types/serviceType'; + +import {DragHandleItem} from 'haengdong-design'; +import {useOutletContext} from 'react-router-dom'; + +import {DeleteMemberActionModal} from '@components/Modal/SetActionModal/DeleteMemberActionModal'; +import {EventPageContextProps} from '@pages/EventPage/EventPageLayout'; + +interface MemberStepItemProps { + step: MemberStep; + isOpenBottomSheet: boolean; + setIsOpenBottomSheet: React.Dispatch>; +} + +const MemberStepItem: React.FC = ({step, isOpenBottomSheet, setIsOpenBottomSheet}) => { + const {isAdmin} = useOutletContext(); + + return ( + <> + name).join(', ')} ${step.type === 'IN' ? '๋“ค์–ด์˜ด' : '๋‚˜๊ฐ'}`} + onClick={() => setIsOpenBottomSheet(prev => !prev)} + /> + {isOpenBottomSheet && isAdmin && ( + + )} + + ); +}; + +export default MemberStepItem; diff --git a/client/src/components/StepList/Step.stories.tsx b/client/src/components/StepList/Step.stories.tsx deleted file mode 100644 index 0d2b64bb2..000000000 --- a/client/src/components/StepList/Step.stories.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import {MemoryRouter} from 'react-router-dom'; - -import Step from './Step'; - -const meta = { - title: 'Components/Step', - component: Step, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - step: { - description: '', - }, - isAdmin: { - description: '', - control: {type: 'boolean'}, - }, - }, - args: { - step: { - bills: [ - { - id: 1, - title: '์ปคํ”ผ', - price: 10000, - isFixed: false, - }, - { - id: 2, - title: '์ธ์ƒ๋„ค์ปท', - price: 20000, - isFixed: false, - }, - ], - members: [ - { - id: 1, - name: '๋ง์ตธ', - }, - { - id: 2, - name: '๋ฐฑํ˜ธ', - }, - ], - }, - isAdmin: false, - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = { - render: ({...args}) => { - return ( - -
    - -
    -
    - ); - }, -}; diff --git a/client/src/components/StepList/Step.tsx b/client/src/components/StepList/Step.tsx index 997cf03c7..f6c89475b 100644 --- a/client/src/components/StepList/Step.tsx +++ b/client/src/components/StepList/Step.tsx @@ -1,56 +1,51 @@ -/** @jsxImportSource @emotion/react */ -import {useNavigate} from 'react-router-dom'; -import {css} from '@emotion/react'; +import type {BillStep, MemberStep} from 'types/serviceType'; -import Amount from '@components/Design/components/Amount/Amount'; -import ChipGroup from '@components/Design/components/ChipGroup/ChipGroup'; -import ListItem from '@components/Design/components/ListItem/ListItem'; -import {Bill, Step as StepType} from 'types/serviceType'; +import {useEffect, useState} from 'react'; -import {Text} from '@components/Design'; +import BillStepItem from './BillStepItem'; +import MemberStepItem from './MemberStepItem'; -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -interface Prop { - step: StepType; - isAdmin: boolean; +interface StepProps { + step: BillStep | MemberStep; + isAddEditableItem: boolean; + lastBillItemIndex: number; + lastItemIndex: number; + index: number; + setIsAddEditableItem: React.Dispatch>; } -const Step = ({step, isAdmin}: Prop) => { - const navigate = useNavigate(); - const eventId = getEventIdByUrl(); - const handleClickStep = (bill: Bill) => { - if (isAdmin) navigate(`/event/${eventId}/edit-bill`, {state: {bill}}); - }; - - return ( - - - member.name)} /> - - - {step.members.length}๋ช… - - - {step.bills.map(bill => { - return ( - handleClickStep(bill)}> - {bill.title} - - - ); - })} - - ); +const Step = ({step, isAddEditableItem, lastBillItemIndex, lastItemIndex, setIsAddEditableItem, index}: StepProps) => { + const [isOpenBottomSheet, setIsOpenBottomSheet] = useState(false); + const [isLastBillItem, setIsLastBillItem] = useState(false); + + useEffect(() => { + if (index === lastBillItemIndex && lastBillItemIndex === lastItemIndex) { + // index๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋งˆ์ง€๋ง‰ BillStep์ธ์ง€ ํ™•์ธ + setIsLastBillItem(true); + } else { + setIsLastBillItem(false); + } + }, [index, lastBillItemIndex]); + + if (step.actions && step.type === 'BILL') { + return ( + + ); + } else if (step.actions && (step.type === 'IN' || step.type === 'OUT')) { + return ( + + ); + } else { + return <>; + } }; export default Step; diff --git a/client/src/components/StepList/StepList.tsx b/client/src/components/StepList/StepList.tsx new file mode 100644 index 000000000..d6a507247 --- /dev/null +++ b/client/src/components/StepList/StepList.tsx @@ -0,0 +1,76 @@ +import {Flex} from 'haengdong-design'; +import {useEffect, useMemo, useState} from 'react'; + +import {BillStep, MemberStep} from 'types/serviceType'; +import useRequestGetStepList from '@hooks/queries/useRequestGetStepList'; + +import Step from './Step'; + +interface StepListProps { + isAddEditableItem?: boolean; + setIsAddEditableItem?: React.Dispatch>; +} + +const StepList = ({isAddEditableItem = false, setIsAddEditableItem = () => {}}: StepListProps) => { + const {data: stepListData} = useRequestGetStepList(); + const [stepList, setStepList] = useState<(MemberStep | BillStep)[]>([]); + const existIndexInStepList = stepList.map((step, index) => ({...step, index})); + const [hasAddedItem, setHasAddedItem] = useState(false); + const nextStepName = stepList.length > 0 ? String(stepList[stepList.length - 1].stepName).match(/.*(?=์ฐจ)/) : ''; + + useEffect(() => { + if (stepListData) { + setStepList(stepListData); + } + }, [stepListData]); + + const lastBillItemIndex = useMemo(() => { + const billSteps = existIndexInStepList.filter(step => step.type === 'BILL'); + + // billSteps ๋ฐฐ์—ด์ด ๋น„์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์˜ index๋ฅผ ๋ฐ˜ํ™˜, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด -1์„ ๋ฐ˜ํ™˜ + return billSteps.length > 0 ? billSteps.slice(-1)[0].index : -1; + }, [stepList]); + + const lastItemIndex = useMemo(() => { + return existIndexInStepList.length > 0 ? existIndexInStepList.slice(-1)[0].index : -1; + }, [existIndexInStepList]); + + useEffect(() => { + if (hasAddedItem) { + setHasAddedItem(false); + + setStepList(prev => [...prev.filter(({actions}) => actions.length !== 0)]); + } + + if (isAddEditableItem && lastBillItemIndex !== lastItemIndex && !hasAddedItem) { + setStepList(prev => [ + ...prev, + { + type: 'BILL', + stepName: `${Number(nextStepName) + 1}์ฐจ`, + members: [], + actions: [], + }, + ]); + setHasAddedItem(prev => !prev); + } + }, [isAddEditableItem]); + + return ( + + {stepList.map((step, index) => ( + + ))} + + ); +}; + +export default StepList; diff --git a/client/src/components/StepList/Steps.tsx b/client/src/components/StepList/Steps.tsx deleted file mode 100644 index 308f9fda6..000000000 --- a/client/src/components/StepList/Steps.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import {Step as StepType} from 'types/serviceType'; -import BillEmptyFallback from '@pages/EventPage/EventPageFallback/BillEmptyFallback'; - -import {Flex} from '@HDesign/index'; - -import Step from './Step'; - -interface Props { - data: StepType[]; - isAdmin: boolean; -} - -const Steps = ({data, isAdmin}: Props) => { - if (data.length <= 0 && !isAdmin) { - return ; - } - - return ( - - {data.map((step, index) => ( - - ))} - - ); -}; - -export default Steps; diff --git a/client/src/components/Toast/Toast.style.ts b/client/src/components/Toast/Toast.style.ts index d8c4c62f7..a0b5c7cd4 100644 --- a/client/src/components/Toast/Toast.style.ts +++ b/client/src/components/Toast/Toast.style.ts @@ -1,6 +1,12 @@ import {css, keyframes} from '@emotion/react'; -import {ToastOptions} from 'types/toastType'; +import {ToastPosition} from './Toast.type'; + +type ToastMarginStyle = { + position?: ToastPosition; + bottom?: string; + top?: string; +}; // ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ‚คํ”„๋ ˆ์ž„ ์ •์˜ const fadeInWithTransformY = keyframes` @@ -25,14 +31,13 @@ const fadeOutWithTransformY = keyframes` } `; -export const toastMarginStyle = ({position, bottom, top, theme}: ToastOptions) => +export const toastMarginStyle = ({position, bottom, top}: ToastMarginStyle) => css({ position: 'absolute', bottom: position === 'bottom' ? `${bottom}` : 'auto', top: position === 'top' ? `${top}` : 'auto', left: '50%', transform: 'translate(-50%)', - zIndex: theme?.zIndex.toast, width: '100%', maxWidth: '48rem', diff --git a/client/src/components/Toast/Toast.tsx b/client/src/components/Toast/Toast.tsx index cbc6824f4..5bf44d6fb 100644 --- a/client/src/components/Toast/Toast.tsx +++ b/client/src/components/Toast/Toast.tsx @@ -1,8 +1,6 @@ import {createPortal} from 'react-dom'; import {useState, useEffect} from 'react'; - -import {useTheme} from '@HDesign/index'; -import {Button, Flex, Icon, Text} from '@HDesign/index'; +import {Button, Flex, Icon, Text} from 'haengdong-design'; import {toastStyle, textStyle, toastMarginStyle} from './Toast.style'; import {ToastProps, ToastType} from './Toast.type'; @@ -18,9 +16,8 @@ const ANIMATION_TIME = 500; const Toast = ({ type = 'confirm', top = '0px', - bottom = '6rem', - isCloseOnClick = true, - isAutoClosed = true, + bottom = '0px', + isClickToClose = true, position = 'bottom', showingTime = 3000, message, @@ -28,20 +25,10 @@ const Toast = ({ onClose, ...htmlProps }: ToastProps) => { - const {theme} = useTheme(); const [isVisible, setIsVisible] = useState(true); - const styleProps = {position, top, bottom, theme}; - - const handleClickToClose = () => { - if (!isCloseOnClick || !onClose) return; - - setIsVisible(false); - setTimeout(() => { - onClose(); - }, ANIMATION_TIME); // fadeOut ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ๊ฐ„๊ณผ ๋™์ผํ•˜๊ฒŒ ์„ค์ • - }; + const styleProps = {position, top, bottom}; - const handleAutoClose = () => { + useEffect(() => { const timer = setTimeout(() => { setIsVisible(false); setTimeout(() => { @@ -52,11 +39,16 @@ const Toast = ({ return () => { clearTimeout(timer); }; - }; + }, [onClose]); - useEffect(() => { - if (isAutoClosed) handleAutoClose(); - }, []); + const handleClickToClose = () => { + if (!isClickToClose || !onClose) return; + + setIsVisible(false); + setTimeout(() => { + onClose(); + }, ANIMATION_TIME); // fadeOut ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ๊ฐ„๊ณผ ๋™์ผํ•˜๊ฒŒ ์„ค์ • + }; return createPortal(
    diff --git a/client/src/components/Toast/Toast.type.ts b/client/src/components/Toast/Toast.type.ts index a1ff70c40..20b92c0db 100644 --- a/client/src/components/Toast/Toast.type.ts +++ b/client/src/components/Toast/Toast.type.ts @@ -1,15 +1,22 @@ -import {ToastMessage, ToastOptions} from 'types/toastType'; - +export type ToastPosition = 'bottom' | 'top'; export type ToastType = 'error' | 'confirm' | 'none'; -export type ToastOptionProps = ToastOptions & { +export interface ToastStyleProps { + bottom?: string; + top?: string; +} + +export interface ToastOptionProps { + position?: ToastPosition; type?: ToastType; - onClose?: () => void; onUndo?: () => void; -}; + isClickToClose?: boolean; + onClose?: () => void; + showingTime?: number; +} -export type ToastRequiredProps = { - message: ToastMessage; -}; +export interface ToastRequiredProps { + message: string; +} -export type ToastProps = React.ComponentProps<'div'> & ToastOptionProps & ToastRequiredProps; +export type ToastProps = React.ComponentProps<'div'> & ToastStyleProps & ToastOptionProps & ToastRequiredProps; diff --git a/client/src/components/Toast/ToastContainer.tsx b/client/src/components/Toast/ToastContainer.tsx deleted file mode 100644 index 40439f9b6..000000000 --- a/client/src/components/Toast/ToastContainer.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import {useToast} from '@hooks/useToast/useToast'; - -import Toast from './Toast'; - -const ToastContainer = () => { - const {currentToast, closeToast} = useToast(); - - return <>{currentToast && }; -}; - -export default ToastContainer; diff --git a/client/src/constants/bank.ts b/client/src/constants/bank.ts deleted file mode 100644 index b730adb44..000000000 --- a/client/src/constants/bank.ts +++ /dev/null @@ -1,32 +0,0 @@ -type Bank = { - name: string; - iconPosition: string; -}; - -const BANKS: Bank[] = [ - {name: '์šฐ๋ฆฌ์€ํ–‰', iconPosition: '-10px -10px'}, - {name: '์ œ์ผ์€ํ–‰', iconPosition: '-110px -10px'}, - {name: '์‹ ํ•œ์€ํ–‰', iconPosition: '-10px -110px'}, - {name: 'KB๊ตญ๋ฏผ์€ํ–‰', iconPosition: '-110px -110px'}, - {name: 'ํ•˜๋‚˜์€ํ–‰', iconPosition: '-210px -10px'}, - {name: '์‹œํ‹ฐ์€ํ–‰', iconPosition: '-210px -110px'}, - {name: 'IM๋ฑ…ํฌ', iconPosition: '-10px -210px'}, - {name: '๋ถ€์‚ฐ์€ํ–‰', iconPosition: '-110px -210px'}, - {name: '๊ฒฝ๋‚จ์€ํ–‰', iconPosition: '-210px -210px'}, - {name: '๊ด‘์ฃผ์€ํ–‰', iconPosition: '-310px -10px'}, - {name: '์ „๋ถ์€ํ–‰', iconPosition: '-310px -110px'}, - {name: '์ œ์ฃผ์€ํ–‰', iconPosition: '-310px -210px'}, - {name: '๊ธฐ์—…์€ํ–‰', iconPosition: '-10px -310px'}, - {name: '์‚ฐ์—…์€ํ–‰', iconPosition: '-110px -310px'}, - {name: '์ˆ˜ํ˜‘์€ํ–‰', iconPosition: '-210px -310px'}, - {name: '๋†ํ˜‘์€ํ–‰', iconPosition: '-310px -310px'}, - {name: '์ƒˆ๋งˆ์„๊ธˆ๊ณ ', iconPosition: '-410px -10px'}, - {name: '์šฐ์ฒด๊ตญ์€ํ–‰', iconPosition: '-410px -110px'}, - {name: '์‹ ํ˜‘์€ํ–‰', iconPosition: '-410px -210px'}, - {name: 'SBI์ €์ถ•', iconPosition: '-410px -310px'}, - {name: '์นด์นด์˜ค๋ฑ…ํฌ', iconPosition: '-10px -410px'}, - {name: 'ํ† ์Šค๋ฑ…ํฌ', iconPosition: '-110px -410px'}, - {name: '์ผ€์ด๋ฑ…ํฌ', iconPosition: '-210px -410px'}, -]; - -export default BANKS; diff --git a/client/src/constants/errorMessage.ts b/client/src/constants/errorMessage.ts index 113b7c7e1..42703bdf0 100644 --- a/client/src/constants/errorMessage.ts +++ b/client/src/constants/errorMessage.ts @@ -1,61 +1,49 @@ -import RULE from './rule'; - type ErrorMessage = Record; export const SERVER_ERROR_MESSAGES: ErrorMessage = { - // ํ–‰์‚ฌ ๊ด€๋ จ ์—๋Ÿฌ ์ฝ”๋“œ - EVENT_NAME_LENGTH_INVALID: `ํ–‰์‚ฌ ์ด๋ฆ„์˜ ๊ธธ์ด๋Š” 2์ž ์ด์ƒ ${RULE.maxEventNameLength}์ž ์ดํ•˜๋งŒ ๊ฐ€๋Šฅํ•ด์š”.`, - EVENT_NAME_CONSECUTIVE_SPACES: 'ํ–‰์‚ฌ ์ด๋ฆ„์—๋Š” ๊ณต๋ฐฑ ๋ฌธ์ž๊ฐ€ ์—ฐ์†๋  ์ˆ˜ ์—†์–ด์š”.', - EVENT_PASSWORD_FORMAT_INVALID: `๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ${RULE.maxEventPasswordLength}์ž๋ฆฌ์˜ ์ˆซ์ž๋งŒ ๊ฐ€๋Šฅํ•ด์š”.`, - EVENT_NOT_FOUND: '์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์—์š”. ๋งํฌ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.', - - // ๋ฉค๋ฒ„ ๊ด€๋ จ ์—๋Ÿฌ ์ฝ”๋“œ - MEMBER_NAME_LENGTH_INVALID: `๋ฉค๋ฒ„ ์ด๋ฆ„์€ ํ•œ๊ธ€ ${RULE.maxEventNameLength}์ž๊นŒ์ง€, ์˜์–ด ${RULE.maxEventNameLength * 2}์ž๊นŒ์ง€ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ด์š”.`, - - MEMBER_NAME_CHANGE_DUPLICATE: '์š”์ฒญ ๋ณธ๋ฌธ์— ์ค‘๋ณต๋œ ์ด๋ฆ„์ด ์กด์žฌํ•ด์š”. \n(ex. [์ด์ƒ, ์ด์ƒ, ๊ฐ์ž, ๋ฐฑํ˜ธ])', - MEMBER_NAME_DUPLICATE: '์š”์ฒญ ๋ณธ๋ฌธ์— ์ค‘๋ณต๋œ ์ด๋ฆ„์ด ์กด์žฌํ•ด์š”. \n(ex. [์ด์ƒ, ์ด์ƒ, ๊ฐ์ž, ๋ฐฑํ˜ธ])', - MEMBER_ALREADY_EXIST: '์ด๋ฏธ ํ–‰์‚ฌ์— ์ฐธ์—ฌ์ค‘์ธ ์ธ์›์ด์—์š”. \n๊ฒน์น˜์ง€ ์•Š๋„๋ก ๋‹ค๋ฅธ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•ด์ฃผ์„ธ์š”.', - - MEMBER_NOT_EXIST: 'ํ˜„์žฌ ์ฐธ์—ฌํ•˜๊ณ  ์žˆ์ง€ ์•Š์€ ์ธ์›์ด ์กด์žฌํ•ด์š”', - MEMBER_UPDATE_MISMATCH: '์—…๋ฐ์ดํŠธ ์š”์ฒญ๋œ ์ฐธ์—ฌ์ž ์ •๋ณด์™€ ๊ธฐ์กด ํ–‰์‚ฌ ์ฐธ์—ฌ์ž ์ •๋ณด๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์•„์š”.', - - // ์ง€์ถœ ๊ด€๋ จ ์—๋Ÿฌ ์ฝ”๋“œ - BILL_NOT_FOUND: '์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ง€์ถœ ์•ก์…˜์ด์—์š”.', - BILL_TITLE_INVALID: `์ง€์ถœ ๋‚ด์—ญ ์ด๋ฆ„์€ 1์ž ์ด์ƒ ${RULE.maxBillNameLength} ์ดํ•˜์—ฌ์•ผ ํ•ด์š”.`, - BILL_PRICE_INVALID: `์ง€์ถœ ๊ธˆ์•ก์€ ${RULE.maxPrice.toLocaleString('ko-KR')} ์ดํ•˜์˜ ์ž์—ฐ์ˆ˜์—ฌ์•ผ ํ•ด์š”.`, - BILL_DETAIL_NOT_FOUND: '์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ฐธ์—ฌ์ž ์ง€์ถœ์ž…๋‹ˆ๋‹ค.', - BILL_PRICE_NOT_MATCHED: '์ง€์ถœ ์ด์•ก์ด ์ผ์น˜ํ•˜์ง€ ์•Š์•„์š”.', - DIFFERENT_STEP_MEMBERS: 'ํšŒ์› ๋ชฉ๋ก์ด ์ผ์น˜ํ•˜์ง€ ์•Š์•„์š”.', - - // ๊ณ„์ขŒ ๊ด€๋ จ ์—๋Ÿฌ ์ฝ”๋“œ - BANK_NAME_INVALID: '์ง€์›ํ•˜์ง€ ์•Š๋Š” ์€ํ–‰์ด์—์š”. ๋‹ค๋ฅธ ์€ํ–‰์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.', - ACCOUNT_LENGTH_INVALID: `๊ณ„์ขŒ ๋ฒˆํ˜ธ๋Š” 8์ž ์ด์ƒ ${RULE.maxAccountNumberLength}์ž ์ดํ•˜๋กœ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ด์š”.`, - - // ๋กœ๊ทธ์ธ ๊ด€๋ จ ์—๋Ÿฌ ์ฝ”๋“œ - TOKEN_NOT_FOUND: '๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•œ ์„œ๋น„์Šค์—์š”.', - TOKEN_EXPIRED: '๋กœ๊ทธ์ธ์ด ๋งŒ๋ฃŒ๋˜์—ˆ์–ด์š”. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.', - TOKEN_INVALID: '๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.', - FORBIDDEN: '์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ํ–‰์‚ฌ์—์š”.', - - // ์‚ฌ์šฉ์ž์—๊ฒŒ ๋œจ๋ฉด ์•ˆ๋˜๋ฉฐ ํ”„๋ก ํŠธ ๊ตฌํ˜„ ๋ฏธ์Šค์ธ ์—๋Ÿฌ ์ฝ”๋“œ - MESSAGE_NOT_READABLE: '์ฝ์„ ์ˆ˜ ์—†๋Š” ์š”์ฒญ์ด์—์š”.', - NO_RESOURCE_REQUEST: '์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ž์›์ด์—์š”.', - REQUEST_METHOD_NOT_SUPPORTED: '์ง€์›ํ•˜์ง€ ์•Š๋Š” ์š”์ฒญ ๋ฉ”์„œ๋“œ์—์š”.', - REQUEST_EMPTY: '์š”์ฒญ ๋ณธ๋ฌธ์— ๋นˆ ๊ฐ’์ด ์กด์žฌํ•ด์š”', - - // ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ์—๋Ÿฌ ์ฝ”๋“œ + EVENT_NOT_FOUND: '์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค.', + EVENT_NAME_LENGTH_INVALID: 'ํ–‰์‚ฌ ์ด๋ฆ„์€ 2์ž ์ด์ƒ 30์ž ์ดํ•˜๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.', + EVENT_NAME_CONSECUTIVE_SPACES: 'ํ–‰์‚ฌ ์ด๋ฆ„์—๋Š” ๊ณต๋ฐฑ ๋ฌธ์ž๊ฐ€ ์—ฐ์†๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.', + EVENT_PASSWORD_FORMAT_INVALID: '๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” 4์ž๋ฆฌ ์ˆซ์ž๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.', + + ACTION_NOT_FOUND: '์กด์žฌํ•˜์ง€ ์•Š๋Š” ์•ก์…˜์ž…๋‹ˆ๋‹ค.', + + MEMBER_NAME_LENGTH_INVALID: '๋ฉค๋ฒ„ ์ด๋ฆ„์€ 1์ž ์ด์ƒ 4์ž ์ดํ•˜๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.', + MEMBER_NAME_DUPLICATE: '์ค‘๋ณต๋œ ํ–‰์‚ฌ ์ฐธ์—ฌ ์ธ์› ์ด๋ฆ„์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.', + MEMBER_NOT_EXIST: 'ํ˜„์žฌ ์ฐธ์—ฌํ•˜๊ณ  ์žˆ์ง€ ์•Š์€ ์ธ์›์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.', + MEMBER_ALREADY_EXIST: 'ํ˜„์žฌ ์ฐธ์—ฌํ•˜๊ณ  ์žˆ๋Š” ์ธ์›์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.', + + MEMBER_ACTION_NOT_FOUND: '์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋ฉค๋ฒ„ ์•ก์…˜์ž…๋‹ˆ๋‹ค.', + MEMBER_ACTION_STATUS_INVALID: '์œ ํšจํ•˜์ง€ ์•Š์€ ๋ฉค๋ฒ„ ์•ก์…˜ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.', + + BILL_ACTION_NOT_FOUND: '์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ง€์ถœ ์•ก์…˜์ž…๋‹ˆ๋‹ค.', + BILL_ACTION_TITLE_INVALID: '์•ž๋’ค ๊ณต๋ฐฑ์„ ์ œ๊ฑฐํ•œ ์ง€์ถœ ๋‚ด์—ญ ์ œ๋ชฉ์€ %d์ž ~ %d์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.', + BILL_ACTION_PRICE_INVALID: '์ง€์ถœ ๊ธˆ์•ก์€ 10,000,000 ์ดํ•˜์˜ ์ž์—ฐ์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.', + + REQUEST_EMPTY: '์ž…๋ ฅ ๊ฐ’์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.', + MESSAGE_NOT_READABLE: '์ฝ์„ ์ˆ˜ ์—†๋Š” ์š”์ฒญ์ž…๋‹ˆ๋‹ค.', + NO_RESOURCE_REQUEST: '์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ž์›์ž…๋‹ˆ๋‹ค.', + REQUEST_METHOD_NOT_SUPPORTED: '์ง€์›ํ•˜์ง€ ์•Š๋Š” ์š”์ฒญ ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.', + INTERNAL_SERVER_ERROR: '์„œ๋ฒ„ ๋‚ด๋ถ€์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.', + + PASSWORD_INVALID: '๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.', + TOKEN_NOT_FOUND: 'ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.', + TOKEN_EXPIRED: '๋งŒ๋ฃŒ๋œ ํ† ํฐ์ž…๋‹ˆ๋‹ค.', + TOKEN_INVALID: '์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค.', + FORBIDDEN: '์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค.', + UNHANDLED: '์•Œ ์ˆ˜ ์—†๋Š” ์—๋Ÿฌ์ž…๋‹ˆ๋‹ค.', }; export const ERROR_MESSAGE = { - eventName: SERVER_ERROR_MESSAGES.EVENT_NAME_LENGTH_INVALID, - eventPasswordType: SERVER_ERROR_MESSAGES.EVENT_PASSWORD_FORMAT_INVALID, - memberName: SERVER_ERROR_MESSAGES.MEMBER_NAME_LENGTH_INVALID, - purchasePrice: `${RULE.maxPrice.toLocaleString('ko-kr')}์› ์ดํ•˜์˜ ์ˆซ์ž๋งŒ ์ž…๋ ฅ์ด ๊ฐ€๋Šฅํ•ด์š”`, - purchaseTitle: `์ง€์ถœ ์ด๋ฆ„์€ ${RULE.maxBillNameLength}์ž ์ดํ•˜์˜ ํ•œ๊ธ€, ์˜์–ด, ์ˆซ์ž๋งŒ ๊ฐ€๋Šฅํ•ด์š”`, + eventName: 'ํ–‰์‚ฌ ์ด๋ฆ„์€ 30์ž ์ดํ•˜๋งŒ ๊ฐ€๋Šฅํ•ด์š”', + eventPasswordType: '๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ์ˆซ์ž๋งŒ ์ž…๋ ฅ์ด ๊ฐ€๋Šฅํ•ด์š”', + memberName: '์ฐธ์—ฌ์ž ์ด๋ฆ„์€ 4์ž ์ดํ•˜์˜ ํ•œ๊ธ€, ์˜์–ด๋งŒ ๊ฐ€๋Šฅํ•ด์š”', + purchasePrice: '10,000,000์› ์ดํ•˜์˜ ์ˆซ์ž๋งŒ ์ž…๋ ฅ์ด ๊ฐ€๋Šฅํ•ด์š”', + purchaseTitle: '์ง€์ถœ ์ด๋ฆ„์€ 30์ž ์ดํ•˜์˜ ํ•œ๊ธ€, ์˜์–ด, ์ˆซ์ž๋งŒ ๊ฐ€๋Šฅํ•ด์š”', preventEmpty: '๊ฐ’์€ ๋น„์–ด์žˆ์„ ์ˆ˜ ์—†์–ด์š”', invalidInput: '์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์€ ์ž…๋ ฅ์ด์—์š”.', - emptyBank: '๊ณ„์ขŒ๋ฒˆํ˜ธ๊ฐ€ ์ž…๋ ฅ๋˜์ง€ ์•Š์•„์„œ\nํ† ์Šค ์†ก๊ธˆ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์–ด์š”', - invalidAccountNumber: '๊ณ„์ขŒ๋ฒˆํ˜ธ๋Š” 8์ž์—์„œ 30์ž ์‚ฌ์ด๋กœ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ด์š”', }; + +export const UNKNOWN_ERROR = 'UNKNOWN_ERROR'; diff --git a/client/src/constants/message.ts b/client/src/constants/message.ts deleted file mode 100644 index d82d48e14..000000000 --- a/client/src/constants/message.ts +++ /dev/null @@ -1,5 +0,0 @@ -const MESSAGE = { - confirmEditEventMember: '์ˆ˜์ •์ด ์™„๋ฃŒ๋˜์—ˆ์–ด์š” :)', -}; - -export default MESSAGE; diff --git a/client/src/constants/queryKeys.ts b/client/src/constants/queryKeys.ts index b0835cfd5..17f3f4586 100644 --- a/client/src/constants/queryKeys.ts +++ b/client/src/constants/queryKeys.ts @@ -1,10 +1,10 @@ const QUERY_KEYS = { - steps: 'steps', - event: 'event', - allMembers: 'allMembers', - currentMembers: 'currentMembers', - reports: 'reports', - billDetails: 'billDetails', + stepList: 'stepList', + eventName: 'eventName', + allMemberList: 'allMemberList', + currentInMember: 'currentInMember', + memberReport: 'memberReport', + memberReportInAction: 'memberReportInAction', }; export default QUERY_KEYS; diff --git a/client/src/constants/regExp.ts b/client/src/constants/regExp.ts index 8a32f3755..4d910ac99 100644 --- a/client/src/constants/regExp.ts +++ b/client/src/constants/regExp.ts @@ -1,9 +1,8 @@ const REGEXP = { eventPassword: /^[0-9]*$/, + memberName: /^[ใ„ฑ-ใ…Žใ…-ใ…ฃ๊ฐ€-ํžฃa-zA-Z\s]*$/, + purchaseTitle: /^[ใ„ฑ-ใ…Žใ…-ใ…ฃ๊ฐ€-ํžฃa-zA-Z0-9\s]*$/, eventUrl: /\/event\/([a-zA-Z0-9-]+)\//, - billTitle: /^([ใ„ฑ-ใ…Ž๊ฐ€-ํžฃa-zA-Z0-9ใ†แ†ข]\s?)*$/, - memberName: /^([ใ„ฑ-ใ…Ž๊ฐ€-ํžฃa-zA-Zใ†แ†ข]\s?)*$/, - accountNumber: /^\d+([\s\-]\d+)*[\s\-]?$/, }; export default REGEXP; diff --git a/client/src/constants/routerUrls.ts b/client/src/constants/routerUrls.ts index 6be509841..6a3634c3b 100644 --- a/client/src/constants/routerUrls.ts +++ b/client/src/constants/routerUrls.ts @@ -1,12 +1,10 @@ export const ROUTER_URLS = { main: '/', - createEvent: '/event/create', - event: '/event', + eventCreateName: '/event/create/name', + eventCreatePassword: '/event/create/password', + eventCreateComplete: '/event/create/complete', + event: '/event', // TODO: (@weadie) baseurl์„ ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ•  ๊ฒƒ์ธ๊ฐ€? eventLogin: '/event/:eventId/login', eventManage: '/event/:eventId/admin', home: '/event/:eventId/home', - member: '/event/:eventId/admin/member', - addBill: '/event/:eventId/add-bill', - editBill: '/event/:eventId/edit-bill', - eventEdit: 'event/:eventId/admin/edit', }; diff --git a/client/src/constants/rule.ts b/client/src/constants/rule.ts index 71ac70c58..4b78031b9 100644 --- a/client/src/constants/rule.ts +++ b/client/src/constants/rule.ts @@ -1,13 +1,8 @@ -const EVENT_PASSWORD_LENGTH = 4; - const RULE = { maxEventNameLength: 30, - maxEventPasswordLength: EVENT_PASSWORD_LENGTH, + maxEventPasswordLength: 4, maxMemberNameLength: 4, maxPrice: 10000000, - maxBillNameLength: 30, - minAccountNumberLength: 8, - maxAccountNumberLength: 30, }; export default RULE; diff --git a/client/src/errors/FetchError.ts b/client/src/errors/FetchError.ts new file mode 100644 index 000000000..9123a80b5 --- /dev/null +++ b/client/src/errors/FetchError.ts @@ -0,0 +1,23 @@ +import {FetchErrorType} from '../types/fetchErrorType'; + +class FetchError extends Error { + requestBody; + status; + endpoint; + errorInfo; + method; + + constructor({requestBody, status, endpoint, errorInfo, method, name, message}: FetchErrorType) { + super(errorInfo.errorCode); + + this.requestBody = requestBody; + this.status = status; + this.endpoint = endpoint; + this.errorInfo = errorInfo; + this.method = method; + this.name = name; + this.message = message; + } +} + +export default FetchError; diff --git a/client/src/errors/RequestError.ts b/client/src/errors/RequestError.ts deleted file mode 100644 index 939b29586..000000000 --- a/client/src/errors/RequestError.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {RequestErrorType} from './requestErrorType'; - -class RequestError extends Error { - requestBody; - status; - endpoint; - method; - errorCode; - message; - - constructor({requestBody, status, endpoint, errorCode, method, name, message}: RequestErrorType) { - super(errorCode); - - this.requestBody = requestBody; - this.status = status; - this.endpoint = endpoint; - this.errorCode = errorCode; - this.message = message; - this.method = method; - this.name = name; - } -} - -export default RequestError; diff --git a/client/src/errors/RequestGetError.ts b/client/src/errors/RequestGetError.ts deleted file mode 100644 index da9a8e10b..000000000 --- a/client/src/errors/RequestGetError.ts +++ /dev/null @@ -1,21 +0,0 @@ -import RequestError from './RequestError'; -import {RequestErrorType} from './requestErrorType'; - -type ErrorHandlingStrategy = 'toast' | 'errorBoundary'; - -export type WithErrorHandlingStrategy

    = P & { - errorHandlingStrategy?: ErrorHandlingStrategy; -}; - -class RequestGetError extends RequestError { - errorHandlingStrategy: string; - - // errorHandlingType์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ์ผ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” toast๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค. - constructor({errorHandlingStrategy = 'toast', ...rest}: WithErrorHandlingStrategy) { - super(rest); - - this.errorHandlingStrategy = errorHandlingStrategy; - } -} - -export {RequestGetError}; diff --git a/client/src/errors/requestErrorType.ts b/client/src/errors/requestErrorType.ts deleted file mode 100644 index 22c9f05f5..000000000 --- a/client/src/errors/requestErrorType.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {Body, Method} from '@apis/fetcher'; - -export type RequestErrorType = Error & { - requestBody: Body; - status: number; - endpoint: string; - errorCode: string; - message: string; - method?: Method; -}; diff --git a/client/src/global.d.ts b/client/src/global.d.ts index 63226360f..dbf6320af 100644 --- a/client/src/global.d.ts +++ b/client/src/global.d.ts @@ -1,5 +1,4 @@ declare module '*.svg'; -declare module '*.png'; declare namespace NodeJS { interface ProcessEnv { @@ -8,6 +7,5 @@ declare namespace NodeJS { // env keys readonly API_BASE_URL: string; readonly AMPLITUDE_KEY: string; - readonly KAKAO_JAVASCRIPT_KEY: string; } } diff --git a/client/src/hooks/queries/bill/useRequestDeleteBill.ts b/client/src/hooks/queries/bill/useRequestDeleteBill.ts deleted file mode 100644 index 68083d52b..000000000 --- a/client/src/hooks/queries/bill/useRequestDeleteBill.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {useMutation, useQueryClient} from '@tanstack/react-query'; - -import {requestDeleteBill} from '@apis/request/bill'; - -import {WithBillId} from '@apis/withId.type'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestDeleteBill = () => { - const eventId = getEventIdByUrl(); - const queryClient = useQueryClient(); - - const {mutate, ...rest} = useMutation({ - mutationFn: ({billId}: WithBillId) => requestDeleteBill({eventId, billId}), - onSuccess: () => { - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.steps]}); - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.reports]}); - }, - }); - - return { - deleteBill: mutate, - ...rest, - }; -}; - -export default useRequestDeleteBill; diff --git a/client/src/hooks/queries/bill/useRequestGetBillDetails.ts b/client/src/hooks/queries/bill/useRequestGetBillDetails.ts deleted file mode 100644 index e59b10437..000000000 --- a/client/src/hooks/queries/bill/useRequestGetBillDetails.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {useQuery} from '@tanstack/react-query'; - -import {requestGetBillDetails} from '@apis/request/bill'; -import {WithErrorHandlingStrategy} from '@errors/RequestGetError'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -type UseRequestGetBillDetails = { - billId: number; -}; - -const useRequestGetBillDetails = ({billId, ...props}: WithErrorHandlingStrategy) => { - const eventId = getEventIdByUrl(); - - const {data, ...rest} = useQuery({ - queryKey: [QUERY_KEYS.billDetails, billId], - queryFn: () => requestGetBillDetails({eventId, billId, ...props}), - }); - - return { - members: data?.members ?? [], - ...rest, - }; -}; - -export default useRequestGetBillDetails; diff --git a/client/src/hooks/queries/bill/useRequestPostBill.ts b/client/src/hooks/queries/bill/useRequestPostBill.ts deleted file mode 100644 index a9c7bce62..000000000 --- a/client/src/hooks/queries/bill/useRequestPostBill.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {useMutation, useQueryClient} from '@tanstack/react-query'; - -import {RequestPostBill, requestPostBill} from '@apis/request/bill'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestPostBill = () => { - const eventId = getEventIdByUrl(); - const queryClient = useQueryClient(); - - const {mutate, ...rest} = useMutation({ - mutationFn: ({title, price, memberIds}: RequestPostBill) => requestPostBill({eventId, title, price, memberIds}), - onSuccess: () => { - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.steps]}); - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.reports]}); - }, - }); - - return { - postBill: mutate, - ...rest, - }; -}; - -export default useRequestPostBill; diff --git a/client/src/hooks/queries/bill/useRequestPutBill.ts b/client/src/hooks/queries/bill/useRequestPutBill.ts deleted file mode 100644 index 88a47f6bf..000000000 --- a/client/src/hooks/queries/bill/useRequestPutBill.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {useMutation, useQueryClient} from '@tanstack/react-query'; - -import {RequestPutBill, requestPutBill} from '@apis/request/bill'; - -import {WithBillId} from '@apis/withId.type'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestPutBill = () => { - const eventId = getEventIdByUrl(); - const queryClient = useQueryClient(); - - const {mutate, mutateAsync, ...rest} = useMutation({ - mutationFn: ({billId, title, price}: WithBillId) => requestPutBill({eventId, billId, title, price}), - onSuccess: () => { - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.steps]}); - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.reports]}); - }, - }); - - return {putBill: mutate, putBillAsync: mutateAsync, ...rest}; -}; - -export default useRequestPutBill; diff --git a/client/src/hooks/queries/bill/useRequestPutBillDetails.ts b/client/src/hooks/queries/bill/useRequestPutBillDetails.ts deleted file mode 100644 index 9e9bb3e0f..000000000 --- a/client/src/hooks/queries/bill/useRequestPutBillDetails.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {useMutation, useQueryClient} from '@tanstack/react-query'; - -import {RequestPutBillDetails, requestPutBillDetails} from '@apis/request/bill'; - -import {WithBillId} from '@apis/withId.type'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestPutBillDetails = ({billId}: WithBillId) => { - const eventId = getEventIdByUrl(); - const queryClient = useQueryClient(); - - const {mutate, ...rest} = useMutation({ - mutationFn: ({billId, billDetails}: WithBillId) => - requestPutBillDetails({eventId, billId, billDetails}), - onSuccess: () => { - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.steps]}); - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.reports]}); - queryClient.removeQueries({queryKey: [QUERY_KEYS.billDetails, billId]}); - }, - // onMutate: async (newMembers: MemberReportInAction[]) => { - // await queryClient.cancelQueries({queryKey: [QUERY_KEYS.memberReportInAction, actionId]}); - - // const previousMembers = queryClient.getQueryData([QUERY_KEYS.memberReportInAction, actionId]); - - // queryClient.setQueryData([QUERY_KEYS.memberReportInAction, actionId], (oldData: MemberReportList) => ({ - // ...oldData, - // members: oldData.members.map((member: MemberReportInAction) => { - // const updatedMember = newMembers.find(m => m.name === member.name); - // return updatedMember ? {...member, ...updatedMember} : member; - // }), - // })); - - // return {previousMembers}; - // }, - // onError: (err, newMembers, context) => { - // if (context?.previousMembers) { - // queryClient.setQueryData([QUERY_KEYS.memberReportInAction, actionId], context.previousMembers); - // } - // }, - }); - - return {putBillDetails: mutate, ...rest}; -}; - -export default useRequestPutBillDetails; diff --git a/client/src/hooks/queries/event/useRequestGetEvent.ts b/client/src/hooks/queries/event/useRequestGetEvent.ts deleted file mode 100644 index 4ce9cd259..000000000 --- a/client/src/hooks/queries/event/useRequestGetEvent.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {useQuery} from '@tanstack/react-query'; - -import {requestGetEvent} from '@apis/request/event'; -import {WithErrorHandlingStrategy} from '@errors/RequestGetError'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestGetEvent = ({...props}: WithErrorHandlingStrategy | null = {}) => { - const eventId = getEventIdByUrl(); - - const {data, ...rest} = useQuery({ - queryKey: [QUERY_KEYS.event], - queryFn: () => requestGetEvent({eventId, ...props}), - }); - - return { - eventName: data?.eventName ?? '', - bankName: data?.bankName ?? '', - accountNumber: data?.accountNumber ?? '', - ...rest, - }; -}; - -export default useRequestGetEvent; diff --git a/client/src/hooks/queries/event/useRequestPatchEvent.ts b/client/src/hooks/queries/event/useRequestPatchEvent.ts deleted file mode 100644 index e09a19c8b..000000000 --- a/client/src/hooks/queries/event/useRequestPatchEvent.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type {Event} from 'types/serviceType'; - -import {useMutation, useQueryClient} from '@tanstack/react-query'; - -import {requestPatchEvent} from '@apis/request/event'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestPatchEventOutline = () => { - const eventId = getEventIdByUrl(); - - const queryClient = useQueryClient(); - - const {mutateAsync, ...rest} = useMutation({ - mutationFn: (eventOutline: Partial) => requestPatchEvent({eventId, eventOutline}), - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: [QUERY_KEYS.event], - }); - }, - }); - - return { - patchEventOutline: mutateAsync, - ...rest, - }; -}; - -export default useRequestPatchEventOutline; diff --git a/client/src/hooks/queries/event/useRequestPostEvent.ts b/client/src/hooks/queries/event/useRequestPostEvent.ts deleted file mode 100644 index d59f6b913..000000000 --- a/client/src/hooks/queries/event/useRequestPostEvent.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {useMutation} from '@tanstack/react-query'; - -import {RequestPostEvent, requestPostEvent} from '@apis/request/event'; - -const useRequestPostEvent = () => { - const {mutate, mutateAsync, ...rest} = useMutation({ - mutationFn: ({eventName, password}: RequestPostEvent) => requestPostEvent({eventName, password}), - }); - - // ์‹คํ–‰ ์ˆœ์„œ๋ฅผ await์œผ๋กœ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด mutateAsync ์‚ฌ์šฉ - return { - postEvent: mutateAsync, - isPostEventPending: rest.isPending, - ...rest, - }; -}; - -export default useRequestPostEvent; diff --git a/client/src/hooks/queries/member/useRequestDeleteMember.ts b/client/src/hooks/queries/member/useRequestDeleteMember.ts deleted file mode 100644 index 770218e6b..000000000 --- a/client/src/hooks/queries/member/useRequestDeleteMember.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {useMutation, useQueryClient} from '@tanstack/react-query'; - -import {RequestDeleteMember, requestDeleteMember} from '@apis/request/member'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestDeleteMember = () => { - const eventId = getEventIdByUrl(); - const queryClient = useQueryClient(); - - const {mutateAsync, ...rest} = useMutation({ - mutationFn: ({memberId}: RequestDeleteMember) => requestDeleteMember({eventId, memberId}), - onSuccess: () => { - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.steps]}); - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.allMembers]}); - queryClient.removeQueries({queryKey: [QUERY_KEYS.billDetails]}); - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.reports]}); - }, - }); - - return {deleteAsyncMember: mutateAsync, ...rest}; -}; - -export default useRequestDeleteMember; diff --git a/client/src/hooks/queries/member/useRequestGetAllMembers.ts b/client/src/hooks/queries/member/useRequestGetAllMembers.ts deleted file mode 100644 index bd28e5836..000000000 --- a/client/src/hooks/queries/member/useRequestGetAllMembers.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {useQuery} from '@tanstack/react-query'; - -import {requestGetAllMembers} from '@apis/request/member'; -import {WithErrorHandlingStrategy} from '@errors/RequestGetError'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestGetAllMembers = ({...props}: WithErrorHandlingStrategy | null = {}) => { - const eventId = getEventIdByUrl(); - - const {data, ...rest} = useQuery({ - queryKey: [QUERY_KEYS.allMembers], - queryFn: () => requestGetAllMembers({eventId, ...props}), - }); - - return {members: data?.members ?? [], ...rest}; -}; - -export default useRequestGetAllMembers; diff --git a/client/src/hooks/queries/member/useRequestGetCurrentMembers.ts b/client/src/hooks/queries/member/useRequestGetCurrentMembers.ts deleted file mode 100644 index 536438b36..000000000 --- a/client/src/hooks/queries/member/useRequestGetCurrentMembers.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {useQuery} from '@tanstack/react-query'; - -import {requestGetCurrentMembers} from '@apis/request/member'; -import {WithErrorHandlingStrategy} from '@errors/RequestGetError'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestGetCurrentMembers = ({...props}: WithErrorHandlingStrategy | null = {}) => { - const eventId = getEventIdByUrl(); - - const {data, ...rest} = useQuery({ - queryKey: [QUERY_KEYS.currentMembers], - queryFn: () => requestGetCurrentMembers({eventId, ...props}), - }); - - return {currentMembers: data?.members ?? [], ...rest}; -}; - -export default useRequestGetCurrentMembers; diff --git a/client/src/hooks/queries/member/useRequestPostMembers.ts b/client/src/hooks/queries/member/useRequestPostMembers.ts deleted file mode 100644 index bddb9a322..000000000 --- a/client/src/hooks/queries/member/useRequestPostMembers.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {useMutation, useQueryClient} from '@tanstack/react-query'; - -import {RequestPostMembers, requestPostMembers} from '@apis/request/member'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestPostMembers = () => { - const eventId = getEventIdByUrl(); - const queryClient = useQueryClient(); - - const {mutate, mutateAsync, data, ...rest} = useMutation({ - mutationFn: ({members}: RequestPostMembers) => requestPostMembers({eventId, members}), - onSuccess: responseData => { - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.allMembers]}); - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.steps]}); - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.reports]}); - return responseData; - }, - }); - - return {postMembers: mutate, postMembersAsync: mutateAsync, responseMemberIds: data, ...rest}; -}; - -export default useRequestPostMembers; diff --git a/client/src/hooks/queries/member/useRequestPutMembers.ts b/client/src/hooks/queries/member/useRequestPutMembers.ts deleted file mode 100644 index 69df92c4c..000000000 --- a/client/src/hooks/queries/member/useRequestPutMembers.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {useMutation, useQueryClient} from '@tanstack/react-query'; - -import {RequestPutMembers, requestPutMembers} from '@apis/request/member'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestPutMembers = () => { - const eventId = getEventIdByUrl(); - const queryClient = useQueryClient(); - - const {mutateAsync, ...rest} = useMutation({ - mutationFn: ({members}: RequestPutMembers) => requestPutMembers({eventId, members}), - onSuccess: () => { - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.steps]}); - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.allMembers]}); - queryClient.removeQueries({queryKey: [QUERY_KEYS.billDetails]}); - queryClient.invalidateQueries({queryKey: [QUERY_KEYS.reports]}); - }, - }); - - return {putAsyncMember: mutateAsync, ...rest}; -}; - -export default useRequestPutMembers; diff --git a/client/src/hooks/queries/report/useRequestGetReports.ts b/client/src/hooks/queries/report/useRequestGetReports.ts deleted file mode 100644 index e1a91fc74..000000000 --- a/client/src/hooks/queries/report/useRequestGetReports.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {useQuery} from '@tanstack/react-query'; - -import {requestGetReports} from '@apis/request/report'; -import {WithErrorHandlingStrategy} from '@errors/RequestGetError'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import QUERY_KEYS from '@constants/queryKeys'; - -const useRequestGetReports = ({...props}: WithErrorHandlingStrategy | null = {}) => { - const eventId = getEventIdByUrl(); - - const {data, ...rest} = useQuery({ - queryKey: [QUERY_KEYS.reports], - queryFn: () => requestGetReports({eventId, ...props}), - }); - - return { - reports: data?.reports ?? [], - ...rest, - }; -}; -export default useRequestGetReports; diff --git a/client/src/hooks/queries/useRequestDeleteAllMemberList.ts b/client/src/hooks/queries/useRequestDeleteAllMemberList.ts new file mode 100644 index 000000000..da6fc4223 --- /dev/null +++ b/client/src/hooks/queries/useRequestDeleteAllMemberList.ts @@ -0,0 +1,28 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {requestDeleteAllMemberList} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface DeleteAllMemberListMutationProps { + memberName: string; +} + +const useRequestDeleteAllMemberList = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({memberName}: DeleteAllMemberListMutationProps) => requestDeleteAllMemberList({eventId, memberName}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.allMemberList]}); + queryClient.removeQueries({queryKey: [QUERY_KEYS.memberReportInAction]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestDeleteAllMemberList; diff --git a/client/src/hooks/queries/useRequestDeleteBillAction.ts b/client/src/hooks/queries/useRequestDeleteBillAction.ts new file mode 100644 index 000000000..28be9dfd1 --- /dev/null +++ b/client/src/hooks/queries/useRequestDeleteBillAction.ts @@ -0,0 +1,26 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {requestDeleteBillAction} from '@apis/request/bill'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface DeleteBillActionMutationProps { + actionId: number; +} + +const useRequestDeleteBillAction = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({actionId}: DeleteBillActionMutationProps) => requestDeleteBillAction({eventId, actionId}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestDeleteBillAction; diff --git a/client/src/hooks/queries/useRequestDeleteMemberAction.ts b/client/src/hooks/queries/useRequestDeleteMemberAction.ts new file mode 100644 index 000000000..08e69ac1f --- /dev/null +++ b/client/src/hooks/queries/useRequestDeleteMemberAction.ts @@ -0,0 +1,28 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {requestDeleteMemberAction} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface DeleteMemberActionMutationProps { + actionId: number; +} + +const useRequestDeleteMemberAction = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({actionId}: DeleteMemberActionMutationProps) => requestDeleteMemberAction({eventId, actionId}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReportInAction]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.allMemberList]}); + }, + }); +}; + +export default useRequestDeleteMemberAction; diff --git a/client/src/hooks/queries/useRequestGetAllMemberList.ts b/client/src/hooks/queries/useRequestGetAllMemberList.ts new file mode 100644 index 000000000..531285fd6 --- /dev/null +++ b/client/src/hooks/queries/useRequestGetAllMemberList.ts @@ -0,0 +1,18 @@ +import {useQuery} from '@tanstack/react-query'; + +import {requestGetAllMemberList} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestGetAllMemberList = () => { + const eventId = getEventIdByUrl(); + + return useQuery({ + queryKey: [QUERY_KEYS.allMemberList], + queryFn: () => requestGetAllMemberList({eventId}), + }); +}; + +export default useRequestGetAllMemberList; diff --git a/client/src/hooks/queries/useRequestGetCurrentInMemberList.ts b/client/src/hooks/queries/useRequestGetCurrentInMemberList.ts new file mode 100644 index 000000000..31dc058c2 --- /dev/null +++ b/client/src/hooks/queries/useRequestGetCurrentInMemberList.ts @@ -0,0 +1,18 @@ +import {useQuery} from '@tanstack/react-query'; + +import {requestGetCurrentInMemberList} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestGetCurrentInMemberList = () => { + const eventId = getEventIdByUrl(); + + return useQuery({ + queryKey: [QUERY_KEYS.currentInMember], + queryFn: () => requestGetCurrentInMemberList({eventId}), + }); +}; + +export default useRequestGetCurrentInMemberList; diff --git a/client/src/hooks/queries/useRequestGetEventName.ts b/client/src/hooks/queries/useRequestGetEventName.ts new file mode 100644 index 000000000..6ddb21858 --- /dev/null +++ b/client/src/hooks/queries/useRequestGetEventName.ts @@ -0,0 +1,18 @@ +import {useQuery} from '@tanstack/react-query'; + +import {requestGetEventName} from '@apis/request/event'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestGetEventName = () => { + const eventId = getEventIdByUrl(); + + return useQuery({ + queryKey: [QUERY_KEYS.eventName], + queryFn: () => requestGetEventName({eventId}), + }); +}; + +export default useRequestGetEventName; diff --git a/client/src/hooks/queries/useRequestGetMemberReportList.ts b/client/src/hooks/queries/useRequestGetMemberReportList.ts new file mode 100644 index 000000000..fe3372d35 --- /dev/null +++ b/client/src/hooks/queries/useRequestGetMemberReportList.ts @@ -0,0 +1,17 @@ +import {useQuery} from '@tanstack/react-query'; + +import {requestGetMemberReportList} from '@apis/request/report'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestGetMemberReportList = () => { + const eventId = getEventIdByUrl(); + + return useQuery({ + queryKey: [QUERY_KEYS.memberReport], + queryFn: () => requestGetMemberReportList({eventId}), + }); +}; +export default useRequestGetMemberReportList; diff --git a/client/src/hooks/queries/useRequestGetMemberReportListInAction.ts b/client/src/hooks/queries/useRequestGetMemberReportListInAction.ts new file mode 100644 index 000000000..85b458228 --- /dev/null +++ b/client/src/hooks/queries/useRequestGetMemberReportListInAction.ts @@ -0,0 +1,24 @@ +import {useQuery} from '@tanstack/react-query'; + +import {requestGetMemberReportListInAction} from '@apis/request/bill'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestGetMemberReportListInAction = (actionId: number) => { + const eventId = getEventIdByUrl(); + + const {data, ...queryResult} = useQuery({ + queryKey: [QUERY_KEYS.memberReportInAction, actionId], + queryFn: () => requestGetMemberReportListInAction({eventId, actionId}), + select: data => data.members, + }); + + return { + memberReportListInActionFromServer: data ?? [], + queryResult, + }; +}; + +export default useRequestGetMemberReportListInAction; diff --git a/client/src/hooks/queries/step/useRequestGetSteps.ts b/client/src/hooks/queries/useRequestGetStepList.ts similarity index 60% rename from client/src/hooks/queries/step/useRequestGetSteps.ts rename to client/src/hooks/queries/useRequestGetStepList.ts index 7b70bacef..7dfc1799c 100644 --- a/client/src/hooks/queries/step/useRequestGetSteps.ts +++ b/client/src/hooks/queries/useRequestGetStepList.ts @@ -1,8 +1,7 @@ import {useQuery} from '@tanstack/react-query'; import {useEffect} from 'react'; -import {requestGetSteps} from '@apis/request/step'; -import {WithErrorHandlingStrategy} from '@errors/RequestGetError'; +import {requestGetStepList} from '@apis/request/stepList'; import {useTotalExpenseAmountStore} from '@store/totalExpenseAmountStore'; @@ -10,13 +9,13 @@ import getEventIdByUrl from '@utils/getEventIdByUrl'; import QUERY_KEYS from '@constants/queryKeys'; -const useRequestGetSteps = ({...props}: WithErrorHandlingStrategy | null = {}) => { +const useRequestGetStepList = () => { const eventId = getEventIdByUrl(); const {updateTotalExpenseAmount} = useTotalExpenseAmountStore(); const queryResult = useQuery({ - queryKey: [QUERY_KEYS.steps], - queryFn: () => requestGetSteps({eventId, ...props}), + queryKey: [QUERY_KEYS.stepList], + queryFn: () => requestGetStepList({eventId}), }); useEffect(() => { @@ -25,10 +24,7 @@ const useRequestGetSteps = ({...props}: WithErrorHandlingStrategy | null = {}) = } }, [queryResult.data, queryResult.isSuccess, updateTotalExpenseAmount]); - return { - steps: queryResult.data ?? [], - ...queryResult, - }; + return queryResult; }; -export default useRequestGetSteps; +export default useRequestGetStepList; diff --git a/client/src/hooks/queries/auth/useRequestPostAuthentication.ts b/client/src/hooks/queries/useRequestPostAuthentication.ts similarity index 74% rename from client/src/hooks/queries/auth/useRequestPostAuthentication.ts rename to client/src/hooks/queries/useRequestPostAuthentication.ts index b44cfcafc..e533a501b 100644 --- a/client/src/hooks/queries/auth/useRequestPostAuthentication.ts +++ b/client/src/hooks/queries/useRequestPostAuthentication.ts @@ -7,22 +7,17 @@ import getEventIdByUrl from '@utils/getEventIdByUrl'; import {ROUTER_URLS} from '@constants/routerUrls'; -const useRequestPostAuthentication = () => { +const useRequestPostAuthenticate = () => { const eventId = getEventIdByUrl(); const navigate = useNavigate(); - const {mutate, ...rest} = useMutation({ + return useMutation({ mutationFn: () => requestPostAuthentication({eventId}), onError: () => { // ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ navigate(`${ROUTER_URLS.event}/${eventId}/login`); }, }); - - return { - postAuthenticate: mutate, - ...rest, - }; }; -export default useRequestPostAuthentication; +export default useRequestPostAuthenticate; diff --git a/client/src/hooks/queries/useRequestPostBillList.ts b/client/src/hooks/queries/useRequestPostBillList.ts new file mode 100644 index 000000000..676da9d85 --- /dev/null +++ b/client/src/hooks/queries/useRequestPostBillList.ts @@ -0,0 +1,27 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {requestPostBillList} from '@apis/request/bill'; +import {Bill} from 'types/serviceType'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface PostBillActionMutationProps { + billList: Bill[]; +} + +const useRequestPostBillList = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({billList}: PostBillActionMutationProps) => requestPostBillList({eventId, billList}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestPostBillList; diff --git a/client/src/hooks/queries/useRequestPostEvent.ts b/client/src/hooks/queries/useRequestPostEvent.ts new file mode 100644 index 000000000..5327710fc --- /dev/null +++ b/client/src/hooks/queries/useRequestPostEvent.ts @@ -0,0 +1,16 @@ +import {useMutation} from '@tanstack/react-query'; + +import {requestPostNewEvent} from '@apis/request/event'; + +interface PostEventMutationProps { + eventName: string; + password: number; +} + +const usePostEvent = () => { + return useMutation({ + mutationFn: ({eventName, password}: PostEventMutationProps) => requestPostNewEvent({eventName, password}), + }); +}; + +export default usePostEvent; diff --git a/client/src/hooks/queries/auth/useRequestPostLogin.ts b/client/src/hooks/queries/useRequestPostLogin.ts similarity index 65% rename from client/src/hooks/queries/auth/useRequestPostLogin.ts rename to client/src/hooks/queries/useRequestPostLogin.ts index f2f0d7c4c..21dce1791 100644 --- a/client/src/hooks/queries/auth/useRequestPostLogin.ts +++ b/client/src/hooks/queries/useRequestPostLogin.ts @@ -1,24 +1,26 @@ import {useMutation} from '@tanstack/react-query'; import {useNavigate} from 'react-router-dom'; -import {RequestPostToken, requestPostToken} from '@apis/request/auth'; +import {requestPostToken} from '@apis/request/auth'; import getEventIdByUrl from '@utils/getEventIdByUrl'; import {ROUTER_URLS} from '@constants/routerUrls'; +interface PostLoginMutationProps { + password: string; +} + const useRequestPostLogin = () => { const eventId = getEventIdByUrl(); const navigate = useNavigate(); - const {mutate, ...rest} = useMutation({ - mutationFn: ({password}: RequestPostToken) => requestPostToken({eventId, password}), + return useMutation({ + mutationFn: ({password}: PostLoginMutationProps) => requestPostToken({eventId, password}), onSuccess: () => { navigate(`${ROUTER_URLS.event}/${eventId}/admin`); }, }); - - return {postLogin: mutate, ...rest}; }; export default useRequestPostLogin; diff --git a/client/src/hooks/queries/useRequestPostMemberList.ts b/client/src/hooks/queries/useRequestPostMemberList.ts new file mode 100644 index 000000000..8ed69db08 --- /dev/null +++ b/client/src/hooks/queries/useRequestPostMemberList.ts @@ -0,0 +1,37 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {MemberType} from 'types/serviceType'; +import {requestPostMemberList} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface PostMemberListMutationProps { + type: MemberType; + memberNameList: string[]; +} + +const useRequestPostMemberList = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({type, memberNameList}: PostMemberListMutationProps) => + requestPostMemberList({eventId, type, memberNameList}), + // TODO: (@todari) : ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ ์ ๊ณ  ์žˆ์—ˆ์–ด์šฉ + // onMutate: async ({type, memberNameList}) => { + // await queryClient.cancelQueries({queryKey: [QUERY_KEYS.stepList]}); + // const previousStepList = queryClient.getQueryData([QUERY_KEYS.stepList]); + // queryClient.setQueryData([QUERY_KEYS.stepList], (prev: (MemberStep | BillStep)[]) => prev && { + // }); + // }, + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.allMemberList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestPostMemberList; diff --git a/client/src/hooks/queries/useRequestPutAllMemberList.ts b/client/src/hooks/queries/useRequestPutAllMemberList.ts new file mode 100644 index 000000000..4bd746d0c --- /dev/null +++ b/client/src/hooks/queries/useRequestPutAllMemberList.ts @@ -0,0 +1,28 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {MemberChange, requestPutAllMemberList} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface PutAllMemberListMutationProps { + members: MemberChange[]; +} + +const useRequestPutAllMemberList = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({members}: PutAllMemberListMutationProps) => requestPutAllMemberList({eventId, members}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.allMemberList]}); + queryClient.removeQueries({queryKey: [QUERY_KEYS.memberReportInAction]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestPutAllMemberList; diff --git a/client/src/hooks/queries/useRequestPutBillAction.ts b/client/src/hooks/queries/useRequestPutBillAction.ts new file mode 100644 index 000000000..a58da8ea4 --- /dev/null +++ b/client/src/hooks/queries/useRequestPutBillAction.ts @@ -0,0 +1,29 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {requestPutBillAction} from '@apis/request/bill'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface PutBillActionMutationProps { + actionId: number; + title: string; + price: number; +} + +const useRequestPutBillAction = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({actionId, title, price}: PutBillActionMutationProps) => + requestPutBillAction({eventId, actionId, title, price}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestPutBillAction; diff --git a/client/src/hooks/queries/useRequestPutMemberReportListInAction.ts b/client/src/hooks/queries/useRequestPutMemberReportListInAction.ts new file mode 100644 index 000000000..a87fa44f1 --- /dev/null +++ b/client/src/hooks/queries/useRequestPutMemberReportListInAction.ts @@ -0,0 +1,49 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {MemberReportList, requestPutMemberReportListInAction} from '@apis/request/bill'; +import {MemberReportInAction} from 'types/serviceType'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestPutMemberReportListInAction = (actionId: number) => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + const {mutate, ...mutationProps} = useMutation({ + mutationFn: (members: MemberReportInAction[]) => requestPutMemberReportListInAction({eventId, actionId, members}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + queryClient.removeQueries({queryKey: [QUERY_KEYS.memberReportInAction, actionId]}); + }, + onMutate: async (newMembers: MemberReportInAction[]) => { + await queryClient.cancelQueries({queryKey: [QUERY_KEYS.memberReportInAction, actionId]}); + + const previousMembers = queryClient.getQueryData([QUERY_KEYS.memberReportInAction, actionId]); + + queryClient.setQueryData([QUERY_KEYS.memberReportInAction, actionId], (oldData: MemberReportList) => ({ + ...oldData, + members: oldData.members.map((member: MemberReportInAction) => { + const updatedMember = newMembers.find(m => m.name === member.name); + return updatedMember ? {...member, ...updatedMember} : member; + }), + })); + + return {previousMembers}; + }, + onError: (err, newMembers, context) => { + if (context?.previousMembers) { + queryClient.setQueryData([QUERY_KEYS.memberReportInAction, actionId], context.previousMembers); + } + }, + }); + + return { + putMemberReportListInAction: mutate, + mutationProps, + }; +}; + +export default useRequestPutMemberReportListInAction; diff --git a/client/src/hooks/useAccount.ts b/client/src/hooks/useAccount.ts deleted file mode 100644 index 418656cc5..000000000 --- a/client/src/hooks/useAccount.ts +++ /dev/null @@ -1,97 +0,0 @@ -import type {Event} from 'types/serviceType'; - -import {useEffect, useState} from 'react'; - -import validateAccountNumber from '@utils/validate/validateAccountNumber'; - -import RULE from '@constants/rule'; - -import useRequestPatchEvent from './queries/event/useRequestPatchEvent'; -import useRequestGetEvent from './queries/event/useRequestGetEvent'; - -const useAccount = () => { - const {bankName, accountNumber} = useRequestGetEvent(); - const [bankNameState, setBankName] = useState(bankName); - const [accountNumberState, setAccountNumber] = useState(accountNumber); - const [accountNumberErrorMessage, setAccountNumberErrorMessage] = useState(null); - const [canSubmit, setCanSubmit] = useState(false); - const [isPasting, setIsPasting] = useState(false); - - useEffect(() => { - setBankName(bankName); - setAccountNumber(accountNumber); - }, [bankName, accountNumber]); - - const {patchEventOutline} = useRequestPatchEvent(); - - const selectBank = (name: string) => { - setBankName(name); - }; - - const handleAccount = (event: React.ChangeEvent) => { - if (isPasting) return; - - const newValue = event.target.value; - const {isValid, errorMessage} = validateAccountNumber(newValue); - setAccountNumberErrorMessage(errorMessage); - - const isValidMinLength = newValue.length >= RULE.minAccountNumberLength; - - if (isValid) { - setAccountNumber(event.target.value); - } else if (!isValid && !isValidMinLength) { - setAccountNumber(event.target.value.replace(/[^0-9\s\-]/g, '').trim()); - } - }; - - const handleAccountOnPaste = (event: React.ClipboardEvent) => { - setIsPasting(true); - - const value = `${accountNumberState}${event.clipboardData.getData('text')}`; - const newValue = value.replace(/[^0-9\s\-]/g, '').trim(); - const {isValid, errorMessage} = validateAccountNumber(newValue); - - setAccountNumberErrorMessage(errorMessage); - if (isValid) setAccountNumber(newValue); - - setTimeout(() => setIsPasting(false), 0); - }; - - const getChangedField = () => { - const changedField: Partial = {}; - - if (bankNameState.trim() !== '' && bankName !== bankNameState) { - changedField.bankName = bankNameState; - } - - if (accountNumberState.trim() !== '' && accountNumber !== accountNumberState) { - changedField.accountNumber = accountNumberState; - } - - return changedField; - }; - - const enrollAccount = async () => { - await patchEventOutline(getChangedField()); - }; - - useEffect(() => { - const existEmptyField = bankNameState.trim() === '' || accountNumberState.trim() === ''; - const isChanged = bankName !== bankNameState || accountNumber !== accountNumberState; - - setCanSubmit(!existEmptyField && isChanged && accountNumberErrorMessage === null); - }, [bankName, accountNumber, bankNameState, accountNumberState, accountNumberErrorMessage]); - - return { - bankName: bankNameState, - accountNumber: accountNumberState, - accountNumberErrorMessage, - canSubmit, - selectBank, - handleAccount, - handleAccountOnPaste, - enrollAccount, - }; -}; - -export default useAccount; diff --git a/client/src/hooks/useAddBillFunnel.ts b/client/src/hooks/useAddBillFunnel.ts deleted file mode 100644 index f0b1e87e8..000000000 --- a/client/src/hooks/useAddBillFunnel.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {useEffect, useState} from 'react'; - -import {BillInfo} from '@pages/AddBillFunnel/AddBillFunnel'; - -import useRequestGetCurrentMembers from './queries/member/useRequestGetCurrentMembers'; - -export type BillStep = 'title' | 'price' | 'members'; - -const useAddBillFunnel = () => { - const {currentMembers} = useRequestGetCurrentMembers(); - const [step, setStep] = useState('price'); - const [billInfo, setBillInfo] = useState({ - price: '', - title: '', - members: [], - }); - - useEffect(() => { - document.body.style.overflow = 'hidden'; - - return () => { - document.body.style.overflow = 'auto'; - }; - }, []); - - useEffect(() => { - currentMembers && setBillInfo(prev => ({...prev, members: currentMembers})); - }, [currentMembers]); - - return {step, setStep, billInfo, setBillInfo, currentMembers}; -}; - -export default useAddBillFunnel; diff --git a/client/src/hooks/useCreateEventData.tsx b/client/src/hooks/useCreateEventData.tsx deleted file mode 100644 index fed21d8ae..000000000 --- a/client/src/hooks/useCreateEventData.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import {useState} from 'react'; - -import useSetEventNameStep from './useSetEventNameStep'; - -// ํ–‰์‚ฌ ์ƒ์„ฑ ํŽ˜์ด์ง€์—์„œ ์—ฌ๋Ÿฌ ์Šคํ…์— ๊ฑธ์ณ ์‚ฌ์šฉ๋˜๋Š” ์ƒํƒœ๋ฅผ ์„ ์–ธํ•ด ๋‚ด๋ ค์ฃผ๋Š” ์šฉ๋„์˜ ํ›…์ž…๋‹ˆ๋‹ค. -const useCreateEventData = () => { - const eventNameProps = useSetEventNameStep(); - const [eventToken, setEventToken] = useState(''); - - return { - eventNameProps, - eventToken, - setEventToken, - }; -}; - -export default useCreateEventData; diff --git a/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.test.tsx b/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.test.tsx new file mode 100644 index 000000000..38836f677 --- /dev/null +++ b/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.test.tsx @@ -0,0 +1,139 @@ +import {renderHook, waitFor} from '@testing-library/react'; +import {MemoryRouter} from 'react-router-dom'; +import {act} from 'react'; +import {HDesignProvider} from 'haengdong-design'; + +import {BillStep, MemberAction, MemberStep} from 'types/serviceType'; +import useRequestGetStepList from '@hooks/queries/useRequestGetStepList'; +import AppErrorBoundary from '@components/AppErrorBoundary/ErrorCatcher'; +import QueryClientBoundary from '@components/QueryClientBoundary/QueryClientBoundary'; +import {ToastProvider} from '@hooks/useToast/ToastProvider'; + +import stepListJson from '@mocks/stepList.json'; +import invalidMemberStepListJson from '@mocks/invalidMemberStepList.json'; + +import useDeleteMemberAction from './useDeleteMemberAction'; + +const stepListMockData = stepListJson as (BillStep | MemberStep)[]; +let memberActionList: MemberAction[] = []; + +// filter๋กœ๋Š” type narrowing์ด ์•ˆ๋˜์–ด ๋ถ€๋“์ดํ•˜๊ฒŒ for ๋ฌธ์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. +for (let i = 0; i < stepListMockData.length; i++) { + const curAction = stepListMockData[i]; + if (curAction.type !== 'BILL') curAction.actions.forEach(action => memberActionList.push(action)); +} + +describe('useDeleteMemberAction', () => { + const initializeProvider = (list: MemberAction[] = memberActionList) => + renderHook( + () => { + return { + stepListResult: useRequestGetStepList(), + deleteMemberActionList: useDeleteMemberAction({ + memberActionList: list, + setIsBottomSheetOpened: () => {}, + showToastAlreadyExistMemberAction: () => {}, + showToastExistSameMemberFromAfterStep: () => {}, + }), + }; + }, + { + wrapper: ({children}) => ( + + + + + {children} + + + + + ), + }, + ); + + it('๋ฉค๋ฒ„๋ฅผ ์‚ญ์ œํ•  ๋ฉค๋ฒ„ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•œ๋‹ค.', async () => { + const {result} = initializeProvider(); + + // stepList ๊ฐ’์ด ์ฑ„์›Œ์ง€๊ธธ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค. + await waitFor(() => { + expect(result.current.stepListResult.data).not.toStrictEqual([]); + }); + + act(() => { + const memberAction = { + actionId: 1, + name: '๋ง์ตธ', + price: null, + sequence: 1, + isFixed: false, + }; + + result.current.deleteMemberActionList.addDeleteMemberAction(memberAction); + }); + + expect(result.current.deleteMemberActionList.aliveActionList).not.toContainEqual({ + actionId: 1, + name: '๋ง์ตธ', + price: null, + sequence: 1, + }); + }); + + it('์‚ญ์ œํ•  ๋ฉค๋ฒ„ ๋ชฉ๋ก์— ์žˆ๋Š” ๋ฉค๋ฒ„๋“ค์„ ๋ชจ๋‘ ์‚ญ์ œํ•ด ์‚ญ์ œํ•  ๋ฉค๋ฒ„ ๋ชฉ๋ก์„ ๋น„์šด๋‹ค.', async () => { + const {result} = initializeProvider(); + + // stepList ๊ฐ’์ด ์ฑ„์›Œ์ง€๊ธธ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค. + await waitFor(() => { + expect(result.current.stepListResult.data).not.toStrictEqual([]); + }); + + await act(async () => { + memberActionList.forEach(memberAction => { + result.current.deleteMemberActionList.addDeleteMemberAction(memberAction); + }); + }); + + await act(async () => result.current.deleteMemberActionList.deleteMemberActionList()); + + await waitFor(() => { + expect(result.current.deleteMemberActionList.aliveActionList).toHaveLength(0); + }); + }); + + it('์‚ญ์ œ ์š”์ฒญ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๊ฒฝ์šฐ ์‚ญ์ œํ•  ๋ฉค๋ฒ„ ๋ชฉ๋ก์„ ์ฒ˜์Œ์˜ ์ƒํƒœ๋กœ ๋Œ๋ ค๋†“๋Š”๋‹ค.', async () => { + /** + * ์ด ํ…Œ์ŠคํŠธ๋Š” deleteMemberAction์„ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ๋‚˜๋Š” ๊ฒฝ์šฐ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. + * ์—ฌ๊ธฐ์„œ ์‚ฌ์šฉํ•˜๋Š” stepList ๋ชฉ๋ฐ์ดํ„ฐ๋Š” 999 actionId๋ฅผ ๊ฐ€์ง„ MemberAction์ด ์žˆ๋Š” ๋ฐ์ดํ„ฐ์ž…๋‹ˆ๋‹ค. + * 999 actionId๋Š” ํ˜„์žฌ ๋ชจํ‚น๋˜์–ด์žˆ๋Š” msw์—์„œ ์˜ค๋ฅ˜๋ฅผ ๋ฑ‰๋„๋ก ํ•˜๋Š” id์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์˜ค๋ฅ˜ ์ƒํ™ฉ์„ ์‹œ์—ฐํ•˜๊ธฐ ์œ„ํ•œ ์ž„์˜ ๋ชจํ‚น์ž…๋‹ˆ๋‹ค. + * (999๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ๋Š” ๋ชจ๋‘ ์ •์ƒ ์‘๋‹ต ๋ฐ˜ํ™˜) + */ + + // 999 actionId๋ฅผ ๊ฐ€์ง„ MemberAction์ด ์žˆ๋Š” stepListJson ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด MemberActions []์œผ๋กœ ์ •์ œํ•ฉ๋‹ˆ๋‹ค. + const invalidMemberStepListMockData = invalidMemberStepListJson as (BillStep | MemberStep)[]; + let memberActionList: MemberAction[] = []; + + for (let i = 0; i < invalidMemberStepListMockData.length; i++) { + const curAction = invalidMemberStepListMockData[i]; + if (curAction.type !== 'BILL') curAction.actions.forEach(action => memberActionList.push(action)); + } + + // ์˜ค๋ฅ˜ ๋ฉค๋ฒ„๊ฐ€ ํฌํ•จ๋œ memberAction[]์„ useDeleteMemberAction์˜ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค. + const {result} = initializeProvider(memberActionList); + + // stepList ๊ฐ’์ด ์ฑ„์›Œ์ง€๊ธธ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค. + await waitFor(() => { + expect(result.current.stepListResult.data).not.toStrictEqual([]); + }); + + await act(async () => { + const memberAction = memberActionList[0]; // ํ˜„์žฌ 0๋ฒˆ ์ฐธ์—ฌ์ž๋Š” actionId๊ฐ€ 999 ์ด๊ณ , 999 actionId๋Š” ์„œ๋ฒ„์—์„œ ์—๋Ÿฌ๋ฅผ ๋ฑ‰๋„๋ก ์กฐ์ž‘๋œ ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค. + result.current.deleteMemberActionList.addDeleteMemberAction(memberAction); + }); + + await act(async () => result.current.deleteMemberActionList.deleteMemberActionList()); + + // ์‚ญ์ œ ์š”์ฒญ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— aliveActionList๋ฅผ ์ดˆ๊ธฐ์— ์ฃผ์ž…ํ–ˆ๋˜ ๊ฐ’์œผ๋กœ ๋‹ค์‹œ ๋Œ๋ ค๋†“๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. + expect(result.current.deleteMemberActionList.aliveActionList).toStrictEqual(memberActionList); + }); +}); diff --git a/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.tsx b/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.tsx new file mode 100644 index 000000000..913087a59 --- /dev/null +++ b/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.tsx @@ -0,0 +1,86 @@ +import type {MemberAction} from 'types/serviceType'; + +import {useState} from 'react'; + +import useRequestGetStepList from '@hooks/queries/useRequestGetStepList'; +import useRequestDeleteMemberAction from '@hooks/queries/useRequestDeleteMemberAction'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +type UseDeleteMemberActionProps = { + memberActionList: MemberAction[]; + setIsBottomSheetOpened: React.Dispatch>; + showToastAlreadyExistMemberAction: () => void; + showToastExistSameMemberFromAfterStep: (name: string) => void; +}; + +const useDeleteMemberAction = ({ + memberActionList, + setIsBottomSheetOpened, + showToastAlreadyExistMemberAction, + showToastExistSameMemberFromAfterStep, +}: UseDeleteMemberActionProps) => { + const {data: stepListData} = useRequestGetStepList(); + const stepList = stepListData ?? []; + const {mutate: deleteMemberActionMutate} = useRequestDeleteMemberAction(); + + const [deleteActionList, setDeleteActionList] = useState([]); + + const eventId = getEventIdByUrl(); + + const deleteMemberAction = async (actionId: number) => { + deleteMemberActionMutate( + {actionId}, + { + onError: () => { + setDeleteActionList([]); + }, + }, + ); + setIsBottomSheetOpened(false); + }; + + // TODO: (@cookie: ์ถ”ํ›„์— ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ deleteํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํ•œ ๋ฒˆ์— ๋ชจ์•„์„œ delete ์ฒ˜๋ฆฌํ•˜๊ธฐ (backend์— ๋ฌธ์˜)) + const deleteMemberActionList = async () => { + for (const {actionId} of deleteActionList) { + await deleteMemberAction(actionId); + } + }; + + const checkAlreadyExistMemberAction = (memberAction: MemberAction, showToast: () => void) => { + if (!memberActionList.includes(memberAction)) { + showToast(); + } + }; + + const checkExistSameMemberFromAfterStep = (memberAction: MemberAction, showToast: () => void) => { + if (isExistSameMemberFromAfterStep(memberAction)) { + showToast(); + } + }; + + const addDeleteMemberAction = (memberAction: MemberAction) => { + checkAlreadyExistMemberAction(memberAction, showToastAlreadyExistMemberAction); + checkExistSameMemberFromAfterStep(memberAction, () => showToastExistSameMemberFromAfterStep(memberAction.name)); + setDeleteActionList(prev => [...prev, memberAction]); + }; + + const isExistSameMemberFromAfterStep = (memberAction: MemberAction) => { + const memberActionList = stepList + .filter(step => step.type !== 'BILL') + .map(({actions}) => actions) + .flat(); + const currentActionIndex = memberActionList.findIndex(action => action.actionId === memberAction.actionId); + const memberActionListAfterCurrentAction = memberActionList.slice(Math.max(currentActionIndex - 1, 0)); + const memberNameList = memberActionListAfterCurrentAction.map(({name}) => name); + + return memberNameList.filter(member => member === memberAction.name).length >= 2; + }; + + const aliveActionList = memberActionList.filter( + memberAction => !deleteActionList.some(deleteAction => deleteAction.actionId === memberAction.actionId), + ); + return {aliveActionList, deleteMemberActionList, addDeleteMemberAction}; +}; + +export default useDeleteMemberAction; diff --git a/client/src/hooks/useDynamicInput.tsx b/client/src/hooks/useDynamicInput.tsx new file mode 100644 index 000000000..452add193 --- /dev/null +++ b/client/src/hooks/useDynamicInput.tsx @@ -0,0 +1,142 @@ +import {useEffect, useRef} from 'react'; + +import {ValidateResult} from '@utils/validate/type'; + +import useInput from './useInput'; + +type InputValue = { + value: string; + index: number; +}; + +export type ReturnUseDynamicInput = { + inputList: InputValue[]; + inputRefList: React.MutableRefObject<(HTMLInputElement | null)[]>; + errorMessage: string | null; + canSubmit: boolean; + errorIndexList: number[]; + handleChange: (index: number, value: string) => void; + handleInputChange: (index: number, event: React.ChangeEvent) => void; + deleteEmptyInputElementOnBlur: () => void; + getFilledInputList: (list?: InputValue[]) => InputValue[]; + focusNextInputOnEnter: (e: React.KeyboardEvent, index: number) => void; + setInputValueTargetIndex: (index: number, value: string) => void; + resetInputValue: () => void; +}; + +const useDynamicInput = (validateFunc: (name: string) => ValidateResult): ReturnUseDynamicInput => { + const initialInputList = [{index: 0, value: ''}]; + const inputRefList = useRef<(HTMLInputElement | null)[]>([]); + + const {inputList, errorMessage, errorIndexList, canSubmit, handleChange, setInputList} = useInput({ + validateFunc, + initialInputList, + }); + + useEffect(() => { + if (inputRefList.current.length <= 0) return; + + const lastInput = inputRefList.current[inputRefList.current.length - 1]; + + if (lastInput) { + lastInput.scrollIntoView({behavior: 'smooth', block: 'center'}); + } + }, [inputList]); + + const handleInputChange = (index: number, event: React.ChangeEvent) => { + const {value} = event.target; + + makeNewInputWhenFirstCharacterInput(index, value); + handleChange(index, value); + }; + + const makeNewInputWhenFirstCharacterInput = (index: number, value: string) => { + if (isLastInputFilled(index, value) && value.trim().length !== 0) { + // ๋งˆ์ง€๋ง‰ ์ธํ’‹์ด ํ•œ ์ž๋ผ๋„ ์ฑ„์›Œ์ง„๋‹ค๋ฉด ์ƒˆ๋กœ์šด ์ธํ’‹์„ ์ƒ์„ฑํ•ด ๊ฐ„ํŽธํ•œ ๋‹ค์Œ ์ž…๋ ฅ์„ ์œ ๋„ํ•ฉ๋‹ˆ๋‹ค. + setInputList(prevInputs => { + const updatedInputList = [...prevInputs]; + + // ์ƒˆ๋กœ์šด ์ธ๋ฑ์Šค๋ฅผ inputs ๋ฐฐ์—ด ๊ธธ์ด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์„ค์ • + const newIndex = updatedInputList[updatedInputList.length - 1].index + 1; + + return [...updatedInputList, {index: newIndex, value: ''}]; + }); + } + }; + + const deleteEmptyInputElementOnBlur = () => { + // 0, 1๋ฒˆ input์ด ๊ฐ’์ด ์žˆ๋Š” ์ƒํƒœ์—์„œ ๋‘ input์˜ ๊ฐ’์„ ๋ชจ๋‘ x๋ฒ„ํŠผ์œผ๋กœ ์ œ๊ฑฐํ•ด๋„ input์ด 2๊ฐœ ๋‚จ์•„์žˆ๋Š” ๋ฌธ์ œ๋ฅผ ์œ„ํ•ด ์กฐ๊ฑด๋ฌธ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. + if (getFilledInputList().length === 0 && inputList.length > 1) { + setInputList([{index: 0, value: ''}]); + return; + } + + // *ํ‘œ์‹œ ์กฐ๊ฑด๋ฌธ์€ ์ฒ˜์Œ์— input์„ ํด๋ฆญํ–ˆ๋‹ค๊ฐ€ ๋ธ”๋Ÿฌ์‹œ์ผฐ์„ ๋•Œ filledInputList๊ฐ€ ์•„์˜ˆ ์—†์–ด .index์— ์ ‘๊ทผํ•  ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•œ ์–ผ๋ฆฌ๋ฆฌํ„ด์„ ๋‘์—ˆ์Šต๋‹ˆ๋‹ค. + if (getFilledInputList().length === 0) return; + + if (getFilledInputList().length !== inputList.length) { + setInputList(inputList => { + const filledInputList = getFilledInputList(inputList); + + // ์ƒˆ ์ž…๋ ฅ์˜ ์ธ๋ฑ์Šค๋ฅผ inputs ๊ธธ์ด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์„ค์ • + const newIndex = filledInputList[filledInputList.length - 1].index + 1; + + return [...filledInputList, {index: newIndex, value: ''}]; + }); + } + }; + + const setInputValueTargetIndex = (index: number, value: string) => { + setInputList(prevInputs => { + const updatedInputList = [...prevInputs]; + const targetInput = findInputByIndex(index, updatedInputList); + + targetInput.value = value; + + return updatedInputList; + }); + }; + + const resetInputValue = () => { + setInputList(initialInputList); + }; + + const focusNextInputOnEnter = (e: React.KeyboardEvent, index: number) => { + if (e.nativeEvent.isComposing) return; + + if (e.key === 'Enter') { + inputRefList.current[index + 1]?.focus(); + } + }; + + const findInputByIndex = (index: number, list?: InputValue[]) => { + return (list ?? inputList).filter(input => input.index === index)[0]; + }; + + const getFilledInputList = (list?: InputValue[]) => { + return (list ?? inputList).filter(({value}) => value.trim().length !== 0); + }; + + const isLastInputFilled = (index: number, value: string) => { + const lastInputIndex = inputList[inputList.length - 1].index; + + return value !== '' && index === lastInputIndex; + }; + + return { + inputList, + inputRefList, + errorMessage, + canSubmit, + errorIndexList, + handleInputChange, + handleChange, + deleteEmptyInputElementOnBlur, + getFilledInputList, + focusNextInputOnEnter, + setInputValueTargetIndex, + resetInputValue, + }; +}; + +export default useDynamicInput; diff --git a/client/src/hooks/useEditBillActions.ts b/client/src/hooks/useEditBillActions.ts deleted file mode 100644 index 2b8ba9418..000000000 --- a/client/src/hooks/useEditBillActions.ts +++ /dev/null @@ -1,78 +0,0 @@ -import {useNavigate} from 'react-router-dom'; -import {useEffect} from 'react'; - -import {Bill, BillDetail} from 'types/serviceType'; -import {RequestPutBill} from '@apis/request/bill'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import useRequestPutBill from './queries/bill/useRequestPutBill'; -import useRequestDeleteBill from './queries/bill/useRequestDeleteBill'; -import useRequestPutBillDetails from './queries/bill/useRequestPutBillDetails'; - -interface Props { - bill: Bill; - billDetails: BillDetail[]; - newBill: RequestPutBill; - newBillDetails: BillDetail[]; -} - -const useEditBillActions = ({bill, billDetails, newBill, newBillDetails}: Props) => { - const navigate = useNavigate(); - const eventId = getEventIdByUrl(); - - const {putBillAsync, isSuccess: isSuccessPutBill, isPending: isPendingPutBill} = useRequestPutBill(); - const {deleteBill, isSuccess: isSuccessDeleteBill} = useRequestDeleteBill(); - const { - putBillDetails, - isSuccess: isSusseccPutBillDetails, - isPending: isPendingPutBillDetails, - } = useRequestPutBillDetails({billId: bill.id}); - - const handleClickDelete = () => { - deleteBill({billId: bill.id}); - }; - - const isBillChanged = bill.title !== newBill.title || bill.price !== newBill.price; - const isBillDetailsChanged = JSON.stringify(billDetails) !== JSON.stringify(newBillDetails); - const canSubmit = newBill.price !== 0 && (isBillChanged || isBillDetailsChanged); - - const handleClickUpdate = async () => { - if (isBillChanged) { - await putBillAsync({billId: bill.id, price: newBill.price, title: newBill.title}); - } - if (isBillDetailsChanged) { - putBillDetails({ - billId: bill.id, - billDetails: newBillDetails.map(({id, price, isFixed}) => ({ - id, - price, - isFixed, - })), - }); - } - }; - - useEffect(() => { - if (isSuccessDeleteBill || isSusseccPutBillDetails || (isSuccessPutBill && !isBillDetailsChanged)) { - navigate(`/event/${eventId}/admin`); - } - }, [isSuccessDeleteBill, isSusseccPutBillDetails, isSuccessPutBill, isBillDetailsChanged]); - - const isPendingUpdate = () => { - if (!isBillChanged) { - return isPendingPutBill; - } - - return isPendingPutBill || isPendingPutBillDetails; - }; - - return { - handleClickDelete, - handleClickUpdate, - isPendingUpdate, - canSubmit, - }; -}; - -export default useEditBillActions; diff --git a/client/src/hooks/useEditBillKeyboardAction.ts b/client/src/hooks/useEditBillKeyboardAction.ts deleted file mode 100644 index df971c5a8..000000000 --- a/client/src/hooks/useEditBillKeyboardAction.ts +++ /dev/null @@ -1,45 +0,0 @@ -import {useRef, useState} from 'react'; - -import {BillDetail} from 'types/serviceType'; -import {RequestPutBill} from '@apis/request/bill'; - -import RULE from '@constants/rule'; - -import useEditBillPageScroll from './useEditBillPageScroll'; - -interface Props { - billDetails: BillDetail[]; - newBill: RequestPutBill; - newBillDetails: BillDetail[]; -} - -const useEditBillKeyboardAction = ({newBill, billDetails, newBillDetails}: Props) => { - const [keyboardTargetId, setKeyboardTargetId] = useState(null); - const billDetailsRef = useRef(null); - const {handleScrollToFocus} = useEditBillPageScroll(); - - const handleClickBillDetailInput = (id: number) => { - setKeyboardTargetId(id); - handleScrollToFocus({id, billDetailsRef}); - }; - - const totalFixedPrice = newBillDetails.reduce( - (sum, detail) => (detail.isFixed && detail.id !== keyboardTargetId ? sum + detail.price : sum), - 0, - ); - const keyboardMaxPrice = keyboardTargetId === 0 ? RULE.maxPrice : Math.max(0, newBill.price - totalFixedPrice); - const keyboardInitialValue = - newBillDetails.find(({id}) => id === keyboardTargetId)?.price.toLocaleString('ko-kr') ?? - newBill.price.toLocaleString('ko-kr'); - - return { - handleClickBillDetailInput, - billDetailsRef, - keyboardMaxPrice, - keyboardInitialValue, - keyboardTargetId, - setKeyboardTargetId, - }; -}; - -export default useEditBillKeyboardAction; diff --git a/client/src/hooks/useEditBillPage.ts b/client/src/hooks/useEditBillPage.ts deleted file mode 100644 index 96d9bf25e..000000000 --- a/client/src/hooks/useEditBillPage.ts +++ /dev/null @@ -1,53 +0,0 @@ -import {useLocation} from 'react-router-dom'; - -import {Bill} from 'types/serviceType'; - -import useRequestGetBillDetails from './queries/bill/useRequestGetBillDetails'; -import useEditBillActions from './useEditBillActions'; -import useEditBillKeyboardAction from './useEditBillKeyboardAction'; -import useEditBillState from './useEditBillState'; - -const useEditBillPage = () => { - const location = useLocation(); - - const bill: Bill = location.state.bill; - const {members: billDetails} = useRequestGetBillDetails({billId: bill.id}); - - const {newBill, newBillDetails, handleChangeBillPrice, handleChangeBillTitle, handleChangeBillDetails} = - useEditBillState({bill, billDetails}); - const {handleClickDelete, handleClickUpdate, isPendingUpdate, canSubmit} = useEditBillActions({ - bill, - billDetails, - newBill, - newBillDetails, - }); - - const { - keyboardTargetId, - setKeyboardTargetId, - keyboardMaxPrice, - keyboardInitialValue, - billDetailsRef, - handleClickBillDetailInput, - } = useEditBillKeyboardAction({newBill, newBillDetails, billDetails}); - - return { - newBill, - newBillDetails, - billDetailsRef, - handleChangeBillTitle, - handleChangeBillPrice, - handleChangeBillDetails, - handleClickBillDetailInput, - handleClickDelete, - handleClickUpdate, - isPendingUpdate, - canSubmit, - keyboardInitialValue, - keyboardMaxPrice, - keyboardTargetId, - setKeyboardTargetId, - }; -}; - -export default useEditBillPage; diff --git a/client/src/hooks/useEditBillPageScroll.ts b/client/src/hooks/useEditBillPageScroll.ts deleted file mode 100644 index c2bf905ea..000000000 --- a/client/src/hooks/useEditBillPageScroll.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {useCallback} from 'react'; - -interface Props { - id: number; - billDetailsRef: React.RefObject; -} - -const useEditBillPageScroll = () => { - const handleScrollToFocus = useCallback(({id, billDetailsRef}: Props) => { - setTimeout(() => { - if (billDetailsRef.current) { - const selectedItem = billDetailsRef.current.querySelector(`[data-id="${id}"]`) as HTMLElement; - if (selectedItem) { - const screenHeight = window.screen.height; - const keyboardHeight = 416; - const itemTop = selectedItem.offsetTop; - const itemHeight = selectedItem.offsetHeight; - const itemBottom = itemTop + itemHeight; - const visibleY = screenHeight - keyboardHeight; - - const targetScrollTop = itemBottom < visibleY ? 0 : itemTop - (visibleY - itemHeight) / 2; - - window.scrollTo({ - top: targetScrollTop, - behavior: 'smooth', - }); - } - } - }, 100); - }, []); - - return {handleScrollToFocus}; -}; - -export default useEditBillPageScroll; diff --git a/client/src/hooks/useEditBillState.ts b/client/src/hooks/useEditBillState.ts deleted file mode 100644 index cc7a079a7..000000000 --- a/client/src/hooks/useEditBillState.ts +++ /dev/null @@ -1,95 +0,0 @@ -import {useEffect, useState} from 'react'; - -import {RequestPutBill} from '@apis/request/bill'; -import {Bill, BillDetail} from 'types/serviceType'; - -import REGEXP from '@constants/regExp'; - -interface Props { - bill: Bill; - billDetails: BillDetail[]; -} - -interface HandleChangeBillDetailsProps { - value: string; - keyboardTargetId: number; -} - -const useEditBillState = ({bill, billDetails}: Props) => { - const [newBill, setNewBill] = useState({ - title: bill.title, - price: bill.price, - }); - const [newBillDetails, setNewBillDetails] = useState(billDetails); - - useEffect(() => { - if (billDetails) setNewBillDetails(billDetails); - }, [billDetails]); - - const onTitleInputChange = (value: string) => { - if (REGEXP.billTitle.test(value)) { - setNewBill(prev => ({...prev, title: value})); - } - }; - - const handleChangeBillTitle = (event: React.ChangeEvent) => { - if (event.target.value.length > 12) { - onTitleInputChange(newBill.title.slice(0, 12)); - } else { - onTitleInputChange(event.target.value); - } - }; - - const handleChangeBillPrice = (value: string) => { - if (value === newBill.price.toLocaleString('ko-kr')) return; - - const newPrice = Number(value.replace(/,/g, '')); - setNewBill(prev => ({...prev, price: newPrice})); - - const detailCount = newBillDetails.length; - const basePrice = Math.floor(newPrice / detailCount); - const remainder = newPrice % detailCount; - - setNewBillDetails(prev => - prev.map((detail, index) => ({ - ...detail, - price: index === detailCount - 1 ? basePrice + remainder : basePrice, - isFixed: false, - })), - ); - }; - - const isLastUnfixedMember = (keyboardTargetId: number) => - !newBillDetails.find(({id}) => id === keyboardTargetId)?.isFixed && - newBillDetails.filter(({isFixed}) => isFixed === false).length === 1; - - const handleChangeBillDetails = ({value, keyboardTargetId}: HandleChangeBillDetailsProps) => { - if (isLastUnfixedMember(keyboardTargetId)) return; - if (Number(value.replace(/,/g, '')) === newBillDetails.find(({id}) => id === keyboardTargetId)?.price) return; - setNewBillDetails(prev => { - const updatedDetails = prev.map(detail => - detail.id === keyboardTargetId ? {...detail, price: Number(value.replace(/,/g, '')), isFixed: true} : detail, - ); - - const totalFixedPrice = updatedDetails.reduce((sum, detail) => (detail.isFixed ? sum + detail.price : sum), 0); - - const remainingPrice = newBill.price - totalFixedPrice; - const unfixedCount = updatedDetails.filter(detail => !detail.isFixed).length; - - const unfixedPrice = Math.floor(remainingPrice / unfixedCount); - const lastUnfixedIndex = updatedDetails.map(detail => !detail.isFixed).lastIndexOf(true); - - return updatedDetails.map((detail, index) => { - if (detail.isFixed) return detail; - if (index === lastUnfixedIndex) { - return {...detail, price: remainingPrice - unfixedPrice * (unfixedCount - 1)}; - } - return {...detail, price: unfixedPrice}; - }); - }); - }; - - return {newBill, newBillDetails, handleChangeBillPrice, handleChangeBillTitle, handleChangeBillDetails}; -}; - -export default useEditBillState; diff --git a/client/src/hooks/useEventLogin.ts b/client/src/hooks/useEventLogin.ts index 15d9b2676..ccabe20c1 100644 --- a/client/src/hooks/useEventLogin.ts +++ b/client/src/hooks/useEventLogin.ts @@ -4,18 +4,18 @@ import validateEventPassword from '@utils/validate/validateEventPassword'; import RULE from '@constants/rule'; -import useRequestPostLogin from './queries/auth/useRequestPostLogin'; +import useRequestPostLogin from './queries/useRequestPostLogin'; const useEventLogin = () => { - const [password, setPassword] = useState(''); + const [password, setPassword] = useState(''); const [errorMessage, setErrorMessage] = useState(null); const [canSubmit, setCanSubmit] = useState(false); - const {postLogin} = useRequestPostLogin(); + const {mutate: postLogin} = useRequestPostLogin(); const submitPassword = async (event: React.FormEvent) => { event.preventDefault(); - postLogin({password: String(password).padStart(4, '0')}, {onError: () => setErrorMessage('๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‹€๋ ธ์–ด์š”')}); + postLogin({password}, {onError: () => setErrorMessage('๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‹€๋ ธ์–ด์š”')}); }; const handleChange = (event: React.ChangeEvent) => { diff --git a/client/src/hooks/useEventMember.ts b/client/src/hooks/useEventMember.ts deleted file mode 100644 index 914a39da8..000000000 --- a/client/src/hooks/useEventMember.ts +++ /dev/null @@ -1,121 +0,0 @@ -import {useEffect, useState, useCallback, useMemo} from 'react'; - -import {Report} from 'types/serviceType'; -import validateMemberName from '@utils/validate/validateMemberName'; - -import MESSAGE from '@constants/message'; - -import toast from './useToast/toast'; -import useRequestDeleteMember from './queries/member/useRequestDeleteMember'; -import useRequestPutMembers from './queries/member/useRequestPutMembers'; -import useRequestGetReports from './queries/report/useRequestGetReports'; - -interface ReturnUseEventMember { - reports: Report[]; - canSubmit: boolean; - changeMemberName: (memberId: number, newName: string) => void; - toggleDepositStatus: (memberId: number) => void; - handleDeleteMember: (memberId: number) => void; - updateMembersOnServer: () => void; -} - -const useEventMember = (): ReturnUseEventMember => { - const {reports: initialReports} = useRequestGetReports(); - const {deleteAsyncMember} = useRequestDeleteMember(); - const {putAsyncMember} = useRequestPutMembers(); - - const [reports, setReports] = useState(initialReports); - const [deleteMembers, setDeleteMembers] = useState([]); - - useEffect(() => { - setReports(initialReports); - }, [initialReports]); - - const canSubmit = useMemo(() => { - // ์ค‘๋ณต๋˜๋Š” ์ด๋ฆ„์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ - const hasDuplicateMemberName = (): boolean => { - const nameSet = new Set(reports.map(member => member.memberName)); - return nameSet.size !== reports.length; - }; - - if (hasDuplicateMemberName()) { - // ์ค‘๋ณต ์ด๋ฆ„์ด๋ผ๋ฉด false - return false; - } - - // ์ด๋ฆ„์ด ๊ณต๋ฐฑ์ด๋ผ๋ฉด false - const hasEmptyName = reports.some(report => report.memberName.trim().length === 0); - if (hasEmptyName) return false; - - // ์ดˆ๊ธฐ ๊ฐ’๊ณผ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ - const hasChanges = reports.some(report => - initialReports.find( - initial => - initial.memberId === report.memberId && - (initial.memberName !== report.memberName || initial.isDeposited !== report.isDeposited), - ), - ); - - // ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ์ด ์กด์žฌ ํ˜น์€ ์‚ญ์ œ๋œ member๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด true - return hasChanges || deleteMembers.length > 0; - }, [reports, initialReports, deleteMembers]); - - const changeMemberName = useCallback( - (memberId: number, newName: string) => { - // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ (4์ž ์ดํ•˜) - if (!validateMemberName(newName).isValid) { - return; - } - - setReports(prevReports => - prevReports.map(report => (report.memberId === memberId ? {...report, memberName: newName} : report)), - ); - }, - [setReports, validateMemberName], - ); - - const toggleDepositStatus = useCallback( - (memberId: number) => { - setReports(prevReports => - prevReports.map(report => - report.memberId === memberId ? {...report, isDeposited: !report.isDeposited} : report, - ), - ); - }, - [setReports], - ); - - // ์‚ญ์ œํ•  member๋ฅผ ๋”ฐ๋กœ deleteMembers ์ƒํƒœ์—์„œ id๋งŒ ์ €์žฅ - const handleDeleteMember = useCallback((memberId: number) => { - setDeleteMembers(prev => [memberId, ...prev]); - // ์‚ญ์ œํ•  member๋“ค์˜ ๋ฐ์ดํ„ฐ๋ฅผ reports์—์„œ ์ œ๊ฑฐ - setReports(prevReports => prevReports.filter(report => report.memberId !== memberId)); - }, []); - - const updateMembersOnServer = useCallback(async () => { - // DELETE ์š”์ฒญ ์„ ํ–‰ - // deleteMembers์— ๊ฐ’์ด ํ•˜๋‚˜๋ผ๋„ ์ „์žฌํ•˜๋ฉด ๋ฐ˜๋ณต๋ฌธ์„ ํ†ตํ•ด DELETE api ์š”์ฒญ - if (deleteMembers.length > 0) { - for (const id of deleteMembers) { - await deleteAsyncMember({memberId: id}); - } - } - - // ๋ณ€๊ฒฝ๋œ ๊ฐ’(filteredChangedMembers)์ด ์กด์žฌํ•œ๋‹ค๋ฉด PUT ์š”์ฒญ ์‹คํ–‰ - if (reports.length > 0) { - await putAsyncMember({ - members: reports.map(report => ({ - id: report.memberId, - name: report.memberName, - isDeposited: report.isDeposited, - })), - }); - } - - toast.confirm(MESSAGE.confirmEditEventMember); - }, [deleteMembers, reports, initialReports, deleteAsyncMember, putAsyncMember]); - - return {reports, canSubmit, changeMemberName, handleDeleteMember, updateMembersOnServer, toggleDepositStatus}; -}; - -export default useEventMember; diff --git a/client/src/hooks/useEventPageLayout.ts b/client/src/hooks/useEventPageLayout.ts deleted file mode 100644 index 57fea80d2..000000000 --- a/client/src/hooks/useEventPageLayout.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {useMatch} from 'react-router-dom'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import {ROUTER_URLS} from '@constants/routerUrls'; - -import useRequestGetEvent from './queries/event/useRequestGetEvent'; - -const useEventPageLayout = () => { - const eventId = getEventIdByUrl(); - const {eventName, bankName, accountNumber} = useRequestGetEvent(); - - const isAdmin = useMatch(ROUTER_URLS.eventManage) !== null; - const isLoginPage = useMatch(ROUTER_URLS.eventLogin) !== null; - - const eventOutline = { - eventName, - bankName, - accountNumber, - }; - - return { - eventId, - isAdmin, - isLoginPage, - eventOutline, - }; -}; - -export default useEventPageLayout; diff --git a/client/src/hooks/useFunnel.tsx b/client/src/hooks/useFunnel.tsx deleted file mode 100644 index 1347e59e7..000000000 --- a/client/src/hooks/useFunnel.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import {useState} from 'react'; - -type UseFunnel = { - defaultStep: string; - stepList: string[]; -}; - -type StepProps = { - children: React.ReactNode; - name: string; -}; - -type FunnelProps = { - step: string; - children: React.ReactElement[]; -}; - -const Step = (stepProps: StepProps) => { - return <>{stepProps.children}; -}; - -const Funnel = ({children, step}: FunnelProps) => { - const targetStep = children.find(curStep => curStep.props.name === step); - - if (!targetStep) - throw new Error(`ํ˜„์žฌ ${step} ๋‹จ๊ณ„์— ๋ณด์—ฌ์ค„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Step ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ˜ธ์ถœํ•ด ์‚ฌ์šฉํ•ด์ฃผ์„ธ์š”.`); - - return <>{targetStep}; -}; - -Funnel.Step = Step; - -const useFunnel = ({defaultStep, stepList}: UseFunnel) => { - const [step, setStep] = useState(defaultStep); - - const moveToNextStep = () => { - const curStepIndex = stepList.indexOf(step); - - if (curStepIndex === stepList.length - 1) return; - - setStep(stepList[curStepIndex + 1]); - }; - - const moveToPrevStep = () => { - const curStepIndex = stepList.indexOf(step); - - if (curStepIndex === 0) return; - - setStep(stepList[curStepIndex - 1]); - }; - - return { - Step, - step, - Funnel, - moveToNextStep, - moveToPrevStep, - }; -}; - -export default useFunnel; diff --git a/client/src/hooks/useMemberReportListInAction/useMemberReportInput.tsx b/client/src/hooks/useMemberReportListInAction/useMemberReportInput.tsx new file mode 100644 index 000000000..9c9cd80d9 --- /dev/null +++ b/client/src/hooks/useMemberReportListInAction/useMemberReportInput.tsx @@ -0,0 +1,89 @@ +import type {MemberReportInAction} from 'types/serviceType'; + +import {useEffect, useState} from 'react'; + +import validateMemberReportInAction from '@utils/validate/validateMemberReportInAction'; + +type MemberReportInput = MemberReportInAction & { + index: number; +}; + +type UseMemberReportProps = { + data: MemberReportInAction[]; + addAdjustedMember: (memberReport: MemberReportInAction) => void; + getOnlyOneNotAdjustedRemainMemberIndex: () => number | null; + getIsSamePriceStateAndServerState: () => boolean; + totalPrice: number; +}; + +const useMemberReportInput = ({ + data, + addAdjustedMember, + totalPrice, + getOnlyOneNotAdjustedRemainMemberIndex, + getIsSamePriceStateAndServerState, +}: UseMemberReportProps) => { + const [inputList, setInputList] = useState(data.map((item, index) => ({...item, index}))); + const [canSubmit, setCanSubmit] = useState(false); + + const [canEditList, setCanEditList] = useState([]); + + const onChange = (event: React.ChangeEvent, index: number) => { + const {value} = event.target; + + validateAndAddAdjustedMember(value, index); + }; + + const validateAndAddAdjustedMember = (price: string, index: number) => { + const {isValid} = validateMemberReportInAction(price, totalPrice); + + if (isValid) { + const newInputList = [...inputList]; + newInputList[index].price = Number(price); + setInputList(newInputList); + + const memberReportData: MemberReportInAction = { + name: newInputList[index].name, + price: newInputList[index].price, + isFixed: newInputList[index].isFixed, + }; + addAdjustedMember(memberReportData); + } + }; + + // ์„œ๋ฒ„์™€ ๊ฐ’์ด ๊ฐ™์ง€ ์•Š๊ณ  input price์˜ ์ƒํƒœ๊ฐ€ ๋ชจ๋‘ validํ•˜๋‹ค๋ฉด can submit true + useEffect(() => { + const isSamePriceState = getIsSamePriceStateAndServerState(); + const isAllValid = inputList.every(input => validateMemberReportInAction(String(input.price), totalPrice)); + + setCanSubmit(!isSamePriceState && isAllValid); + }, [inputList]); + + // addAdjustedMember๋กœ ์ธํ•ด data๊ฐ€ ๋ณ€ํ–ˆ์„ ๋•Œ input list์˜ ๊ฐ’์„ ๋งž์ถฐ์ฃผ๊ธฐ ์œ„ํ•จ + useEffect(() => { + setCanSubmit(!getIsSamePriceStateAndServerState()); + setInputList(data.map((item, index) => ({...item, index}))); + + // ๋‚จ์€ ์ธ์›์ด 1๋ช…์ผ ๋•Œ ์ˆ˜์ •์„ ๋ถˆ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ • + const onlyOneIndex = getOnlyOneNotAdjustedRemainMemberIndex(); + + if (data.length !== 0) { + setCanEditList(new Array(data.length).fill(true)); + } + + if (onlyOneIndex !== null) { + const newCanEditList = new Array(data.length).fill(true); + newCanEditList[onlyOneIndex] = false; + setCanEditList(newCanEditList); + } + }, [data]); + + return { + inputList, + onChange, + canEditList, + canSubmit, + }; +}; + +export default useMemberReportInput; diff --git a/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.test.tsx b/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.test.tsx new file mode 100644 index 000000000..78c29ee03 --- /dev/null +++ b/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.test.tsx @@ -0,0 +1,327 @@ +import type {MemberReportInAction} from 'types/serviceType'; + +import {renderHook, waitFor, act} from '@testing-library/react'; +import {MemoryRouter} from 'react-router-dom'; +import {QueryClient, QueryClientProvider} from '@tanstack/react-query'; + +import memberReportListInActionJson from '../../mocks/memberReportListInAction.json'; + +import useMemberReportListInAction from './useMemberReportListInAction'; + +describe('useMemberReportListInActionTest', () => { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: 0, + }, + }, + }); + + const initializeProvider = (actionId: number, totalPrice: number) => + renderHook(() => useMemberReportListInAction(actionId, totalPrice, () => {}), { + wrapper: ({children}) => ( + + {children} + + ), + }); + + const actionId = 123; + const totalPrice = 100000; + + describe('Flow: ์œ ์ €๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๊ฐ’์„ ๋ถˆ๋Ÿฌ์™”์„ ๋•Œ์˜ test', () => { + it('์ดˆ๊ธฐ๊ฐ’์„ ์ •์ƒ์ ์œผ๋กœ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + expect(result.current.memberReportListInAction).toStrictEqual(memberReportListInActionJson); + }); + + it('๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 100์›์œผ๋กœ ๋ฐ”๊พธ๋ฉด ๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์€ 100์›์œผ๋กœ ์„ค์ •๋œ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMember: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMember); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '๋ง์ตธ'); + + expect(targetMember?.price).toBe(100); + }); + + it('๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 100์›์œผ๋กœ ๋ฐ”๊พธ๋ฉด ๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์€ 100์›์œผ๋กœ ์„ค์ •๋˜๊ณ  ๋‚˜๋จธ์ง€ ์ธ์›์˜ ๊ฐ€๊ฒฉ์ด 33,300์›์œผ๋กœ ์„ค์ •๋œ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMember: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMember); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '๋ง์ตธ'); + expect(targetMember?.price).toBe(100); + + const anotherMemberList = result.current.memberReportListInAction.filter(member => member.name !== '๋ง์ตธ'); + + anotherMemberList.forEach(member => { + expect(member.price).toBe(33300); + }); + }); + + it('๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 100์› ์ฟ ํ‚ค์˜ ๊ฐ€๊ฒฉ์„ 100์›์œผ๋กœ ๋ฐ”๊พธ๋ฉด ๋‚˜๋จธ์ง€ ์ธ์›์˜ ๊ฐ€๊ฒฉ์ด 49,900์›์œผ๋กœ ์„ค์ •๋œ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + const adjustedMemberCookie: MemberReportInAction = {name: '์ฟ ํ‚ค', price: 100, isFixed: true}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember(adjustedMemberCookie); + }); + + const anotherMemberList = result.current.memberReportListInAction.filter( + member => !(member.name === '๋ง์ตธ' || member.name === '์ฟ ํ‚ค'), + ); + + anotherMemberList.forEach(member => { + expect(member.price).toBe(49900); + }); + }); + + it('๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 100์› ์ฟ ํ‚ค์˜ ๊ฐ€๊ฒฉ์„ 100์›์œผ๋กœ ๋ฐ”๊พธ๋ฉด ๋‚˜๋จธ์ง€ ์ธ์›์˜ ๊ฐ€๊ฒฉ์ด 49,900์›์œผ๋กœ ์„ค์ •๋œ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + const adjustedMemberCookie: MemberReportInAction = {name: '์ฟ ํ‚ค', price: 100, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember(adjustedMemberCookie); + }); + + const anotherMemberList = result.current.memberReportListInAction.filter( + member => !(member.name === '๋ง์ตธ' || member.name === '์ฟ ํ‚ค'), + ); + + anotherMemberList.forEach(member => { + expect(member.price).toBe(49900); + }); + }); + + it('๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 100์›์œผ๋กœ ๋ฐ”๊พธ๊ณ  ๋‹ค์‹œ ๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 10,000์›์œผ๋กœ ๋ฐ”๊พธ๋ฉด ๋‚˜๋จธ์ง€ ์ธ์›์˜ ๊ฐ€๊ฒฉ์ด 30,000์›์œผ๋กœ ์„ค์ •๋œ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + const adjustedMemberMangchoAfter: MemberReportInAction = {name: '๋ง์ตธ', price: 10000, isFixed: true}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangchoAfter); + }); + + const anotherMemberList = result.current.memberReportListInAction.filter(member => member.name !== '๋ง์ตธ'); + + anotherMemberList.forEach(member => { + expect(member.price).toBe(30000); + }); + }); + }); + + describe('์˜ˆ์™ธ & ์—ฃ์ง€์ผ€์ด์Šค', () => { + it('๋™์ผํ•œ ์ธ์›์˜ ๊ฐ€๊ฒฉ์„ ๋™์ผํ•˜๊ฒŒ ๋ฐ”๊พธ๋ฉด ๋ณ€ํ•จ์—†๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember({...adjustedMemberMangcho, isFixed: true}); + }); + + const anotherMemberList = result.current.memberReportListInAction.filter(member => member.name !== '๋ง์ตธ'); + + expect(anotherMemberList[0].price).toBe(33300); + }); + + it('๋ง์ตธ์—๊ฒŒ 300์›์„ ์ฃผ๋ฉด ๋‚˜๋จธ์ง€ ์‚ฌ๋žŒ๋“ค์€ 33233์›์ด๊ณ  ๋งˆ์ง€๋ง‰ ์‚ฌ๋žŒ์€ 33234์›์ด ๋œ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '๋ง์ตธ', price: 300, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '๋ง์ตธ'); + expect(targetMember?.price).toBe(300); + + const anotherMemberList = result.current.memberReportListInAction.filter( + member => member.name === '์ด์ƒ' || member.name === '์†Œํ•˜', + ); + + anotherMemberList.forEach(member => { + expect(member.price).toBe(33233); + }); + + const lastMember = result.current.memberReportListInAction.find(member => member.name === '์ฟ ํ‚ค'); + + expect(lastMember?.price).toBe(33234); + }); + + it('๋ง์ตธ, ์ฟ ํ‚ค์˜ ๊ฐ€๊ฒฉ์„ 100์›์œผ๋กœ ๋ฐ”๊พผ ํ›„ ๋‹ค์‹œ ์ฟ ํ‚ค์˜ ๊ฐ€๊ฒฉ์„ 33000์›์œผ๋กœ ๋ฐ”๊พธ๋ฉด ์ฟ ํ‚ค์˜ isFixed๋Š” false๊ฐ€ ๋œ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + const adjustedMemberCookie: MemberReportInAction = {name: '์ฟ ํ‚ค', price: 100, isFixed: false}; + const adjustedMemberCookieReset: MemberReportInAction = {name: '์ฟ ํ‚ค', price: 33300, isFixed: true}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember(adjustedMemberCookie); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '์ฟ ํ‚ค'); + + expect(targetMember?.isFixed).toBe(true); + + act(() => { + result.current.addAdjustedMember(adjustedMemberCookieReset); + }); + + const targetMemberReset = result.current.memberReportListInAction.find(member => member.name === '์ฟ ํ‚ค'); + + expect(targetMemberReset?.isFixed).toBe(false); + }); + + it('๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 100์›์œผ๋กœ ๋ฐ”๊พผ ํ›„ ๋‹ค์‹œ ๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 25000์›์œผ๋กœ ๋ฐ”๊พธ๋ฉด ๋ง์ตธ์˜ isFixed๋Š” false๊ฐ€ ๋œ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + const adjustedMemberMangchoAfter: MemberReportInAction = {name: '๋ง์ตธ', price: 25000, isFixed: true}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '๋ง์ตธ'); + expect(targetMember?.isFixed).toBe(true); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangchoAfter); + }); + + const targetMemberReset = result.current.memberReportListInAction.find(member => member.name === '๋ง์ตธ'); + expect(targetMemberReset?.isFixed).toBe(false); + }); + + it('์•„๋ฌด๋„ ์กฐ์ •๋œ ๊ฐ’์ด ์—†๋‹ค๋ฉด ์กฐ์ •๊ฐ’์ด ์žˆ๋Š”์ง€ ํ™•์ธ ๊ฒฐ๊ณผ false๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + expect(result.current.isExistAdjustedPrice()).toBe(false); + }); + + it('๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 100์›์œผ๋กœ ๋ฐ”๊พผ ํ›„ ๋ฆฌ์ŠคํŠธ ์ค‘ ์กฐ์ •๊ฐ’์ด ์žˆ๋Š”์ง€ ํ™•์ธ ๊ฒฐ๊ณผ true๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + expect(result.current.isExistAdjustedPrice()).toBe(true); + }); + }); + + describe('์ง€์ถœ ์ธ์›์ด 2๋ช…์ธ ์ƒํ™ฉ', () => { + const actionId = 1; + const totalPrice = 50000; + + // ๋ง์ตธ ์ด์ƒ + it('๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 100์›์œผ๋กœ ์ˆ˜์ •ํ•œ ๊ฒฝ์šฐ, ์ด์ƒ์˜ ๊ฐ€๊ฒฉ์ด 49900์›์œผ๋กœ ์ˆ˜์ •๋œ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '์ด์ƒ'); + + expect(targetMember?.price).toBe(49900); + }); + + it('๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 100์›์œผ๋กœ ์ˆ˜์ •ํ•˜๊ณ  ๋‹ค์‹œ 200์›์œผ๋กœ ์ˆ˜์ •ํ•œ ๊ฒฝ์šฐ, ์ด์ƒ์˜ ๊ฐ€๊ฒฉ์ด 49800์›์œผ๋กœ ์ˆ˜์ •๋œ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + const adjustedMemberMangchoOther: MemberReportInAction = {name: '๋ง์ตธ', price: 200, isFixed: true}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangchoOther); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '์ด์ƒ'); + + expect(targetMember?.price).toBe(49800); + }); + }); + + // last + describe('onSubmit ์‹คํ–‰ ์‹œ ๋ฐ˜์˜ ํ…Œ์ŠคํŠธ', () => { + it('๋ง์ตธ์˜ ๊ฐ€๊ฒฉ์„ 100์›์œผ๋กœ ๋ฐ”๊พธ๊ณ  ์ €์žฅํ•˜๋ฉด ๋ง์ตธ 100์›์ด ๋ฐ˜์˜๋œ๋‹ค.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '๋ง์ตธ', price: 100, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + await waitFor(() => { + result.current.onSubmit(); + }); + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '๋ง์ตธ'); + expect(targetMember?.price).toBe(100); + }); + }); +}); diff --git a/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.ts b/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.ts new file mode 100644 index 000000000..0e32d740c --- /dev/null +++ b/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.ts @@ -0,0 +1,156 @@ +import type {MemberReportInAction} from 'types/serviceType'; + +import {useEffect, useState} from 'react'; + +import useRequestGetMemberReportListInAction from '@hooks/queries/useRequestGetMemberReportListInAction'; +import useRequestPutMemberReportListInAction from '@hooks/queries/useRequestPutMemberReportListInAction'; + +const useMemberReportListInAction = (actionId: number, totalPrice: number, onClose: () => void) => { + const {memberReportListInActionFromServer, queryResult} = useRequestGetMemberReportListInAction(actionId); + const {putMemberReportListInAction} = useRequestPutMemberReportListInAction(actionId); + + const [memberReportListInAction, setMemberReportListInAction] = useState( + memberReportListInActionFromServer, + ); + + // isFixed๋ฅผ ๋ชจ๋‘ ํ’€๊ณ  ๊ณ„์‚ฐ๊ฐ’์œผ๋กœ ๋ชจ๋‘ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ + const reCalculatePriceByTotalPriceChange = () => { + const {divided, remainder} = calculateDividedPrice(memberReportListInAction.length, 0); + + const resetMemberReportList = [...memberReportListInAction]; + resetMemberReportList.forEach((member, index) => { + if (index !== resetMemberReportList.length - 1) { + member.price = divided; + } else { + member.price = divided + remainder; + } + member.isFixed = false; + }); + + setMemberReportListInAction(resetMemberReportList); + }; + + // ์ด ๊ธˆ์•ก์ด ๋ณ€๋™๋์„ ๋•Œ (์„œ๋ฒ„์—์„œ ์˜จ ๊ฐ’๊ณผ ๋‹ค๋ฅผ ๋•Œ) ์žฌ๊ณ„์‚ฐ ์‹คํ–‰ + useEffect(() => { + const totalPriceFromServer = memberReportListInActionFromServer.reduce((acc, cur) => acc + cur.price, 0); + + if (totalPriceFromServer !== totalPrice && totalPriceFromServer !== 0) { + reCalculatePriceByTotalPriceChange(); + } + }, [totalPrice, memberReportListInActionFromServer]); + + useEffect(() => { + if (queryResult.isSuccess) { + setMemberReportListInAction(memberReportListInActionFromServer); + } + }, [memberReportListInActionFromServer, queryResult.isSuccess]); + + const isExistAdjustedPrice = () => { + return memberReportListInAction.some(member => member.isFixed === true); + }; + + // ์กฐ์ •๋˜์ง€ ์•Š์€ ์ธ์›์ด ๋‹จ 1๋ช…์ธ ๊ฒฝ์šฐ์˜ index + const getOnlyOneNotAdjustedRemainMemberIndex = (): number | null => { + const adjustedPriceCount = getAdjustedMemberCount(memberReportListInAction); + + if (adjustedPriceCount < memberReportListInAction.length - 1) return null; + + return memberReportListInAction.findIndex(member => member.isFixed === false); + }; + + // ์กฐ์ •๊ฐ’ ๋ฉค๋ฒ„์˜ ์ˆ˜๋ฅผ ๊ตฌํ•˜๋Š” ํ•จ์ˆ˜ + const getAdjustedMemberCount = (memberReportListInAction: MemberReportInAction[]) => { + return memberReportListInAction.filter(member => member.isFixed === true).length; + }; + + const addAdjustedMember = (memberReport: MemberReportInAction) => { + const newMemberReportListInAction = memberReportListInAction.map(member => + member.name === memberReport.name ? {...member, price: memberReport.price, isFixed: true} : member, + ); + + calculateAnotherMemberPrice(newMemberReportListInAction); + }; + + const calculateDividedPrice = (remainMemberCount: number, totalAdjustedPrice: number) => { + return { + divided: Math.floor((totalPrice - totalAdjustedPrice) / remainMemberCount), + remainder: (totalPrice - totalAdjustedPrice) % remainMemberCount, + }; + }; + + // ๊ณ„์‚ฐ๊ฐ’์œผ๋กœ ๊ฐ’์„ ๋ณ€๊ฒฝํ–ˆ์„ ๋•Œ isFixed๋ฅผ ํ‘ธ๋Š” ํ•จ์ˆ˜ + // 100 true 33300 true 33300 false 33300 false + const setIsFixedFalseAtResetToDividedPrice = (memberReportListInAction: MemberReportInAction[], divided: number) => { + return memberReportListInAction.map(memberReport => { + if (memberReport.isFixed === true && memberReport.price === divided) { + return {...memberReport, isFixed: false}; + } + + return memberReport; + }); + }; + + const calculateAnotherMemberPrice = (memberReportListInAction: MemberReportInAction[]) => { + // ์ด ์กฐ์ •์น˜ ๊ธˆ์•ก + const totalAdjustedPrice = memberReportListInAction + .filter(memberReport => memberReport.isFixed === true) + .reduce((acc, cur) => acc + cur.price, 0); + + const remainMemberCount = memberReportListInAction.length - getAdjustedMemberCount(memberReportListInAction); + const {divided, remainder} = calculateDividedPrice(remainMemberCount, totalAdjustedPrice); + + const updatedList = memberReportListInAction.map(member => + member.isFixed === true ? member : {...member, price: divided}, + ); + + // ๋‚˜๋จธ์ง€๋ฅผ ์กฐ์ •๋˜์ง€ ์•Š์€ ๋ฉค๋ฒ„ ์ค‘ ๋งˆ์ง€๋ง‰ ๋ฉค๋ฒ„์—๊ฒŒ ์ถ”๊ฐ€ + if (remainder !== 0) { + const nonAdjustedMembers = updatedList.filter(member => member.isFixed === false); + const lastNonAdjustedMemberIndex = updatedList.findIndex( + member => member.name === nonAdjustedMembers[nonAdjustedMembers.length - 1].name, + ); + + if (lastNonAdjustedMemberIndex !== -1) { + updatedList[lastNonAdjustedMemberIndex].price += remainder; + } + } + + // ์กฐ์ •๋์ง€๋งŒ ๊ณ„์‚ฐ๊ฐ’์œผ๋กœ ๊ฐ€๊ฒฉ์ด ๋ณ€ํ•œ ๊ฒฝ์šฐ fixed ์ƒํƒœ๋ฅผ ํ’€์–ด์•ผํ•œ๋‹ค. + const result = setIsFixedFalseAtResetToDividedPrice(updatedList, divided); + setMemberReportListInAction(result); + }; + + const onSubmit = () => { + putMemberReportListInAction(memberReportListInAction); + + onClose(); + }; + + const getIsSamePriceStateAndServerState = () => { + const serverStatePriceList = memberReportListInActionFromServer.map(({price}) => price); + const clientStatePriceList = memberReportListInAction.map(({price}) => price); + + let isSame = true; + + // isArrayEqual์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์ด์œ ๋Š” ์ •๋ ฌ์ด ์˜ํ–ฅ์„ ๋ฐ›์œผ๋ฉด ์•ˆ ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค + for (let i = 0; i < serverStatePriceList.length; i++) { + if (serverStatePriceList[i] !== clientStatePriceList[i]) { + isSame = false; + } + } + + return isSame; + }; + + return { + memberReportListInAction, + addAdjustedMember, + isExistAdjustedPrice, + onSubmit, + getOnlyOneNotAdjustedRemainMemberIndex, + getIsSamePriceStateAndServerState, + queryResult, + }; +}; + +export default useMemberReportListInAction; diff --git a/client/src/hooks/useMembersStep.ts b/client/src/hooks/useMembersStep.ts deleted file mode 100644 index 1fe15d6d9..000000000 --- a/client/src/hooks/useMembersStep.ts +++ /dev/null @@ -1,126 +0,0 @@ -import {RefObject, useEffect, useRef, useState} from 'react'; -import {useNavigate} from 'react-router-dom'; - -import {BillInfo} from '@pages/AddBillFunnel/AddBillFunnel'; -import {Member} from 'types/serviceType'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - -import REGEXP from '@constants/regExp'; - -import useRequestPostMembers from './queries/member/useRequestPostMembers'; -import useRequestPostBill from './queries/bill/useRequestPostBill'; -import {BillStep} from './useAddBillFunnel'; - -interface Props { - billInfo: BillInfo; - setBillInfo: React.Dispatch>; - setStep: React.Dispatch>; - currentMembers: Member[]; -} - -const useMembersStep = ({billInfo, setBillInfo, currentMembers, setStep}: Props) => { - const [errorMessage, setErrorMessage] = useState(''); - const [nameInput, setNameInput] = useState(''); - const inputRef = useRef(null); - - const {postMembersAsync, isPending: isPendingPostMembers} = useRequestPostMembers(); - - const {postBill, isSuccess: isSuccessPostBill, isPending: isPendingPostBill} = useRequestPostBill(); - const navigate = useNavigate(); - const eventId = getEventIdByUrl(); - - const onNameInputChange = (value: string) => { - if (REGEXP.memberName.test(value)) { - setNameInput(value); - } - }; - - const handleNameInputChange = (event: React.ChangeEvent) => { - if (event.target.value.length > 4) { - setErrorMessage('์ด๋ฆ„์€ 4์ž๊นŒ์ง€ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ด์š”'); - onNameInputChange(nameInput.slice(0, 4)); - } else { - setErrorMessage(''); - onNameInputChange(event.target.value); - } - }; - - const canAddMembers = nameInput && nameInput.length <= 4; - - const canSubmitMembers = billInfo.members.length !== 0; - - const setBillInfoMemberWithId = (name: string) => { - const existingMember = currentMembers.find(currentMember => currentMember.name === name); - if (existingMember) { - setBillInfo(prev => ({...prev, members: [...prev.members, {id: existingMember.id, name: name}]})); - } else { - setBillInfo(prev => ({...prev, members: [...prev.members, {id: -1, name: name}]})); - } - }; - - const handleNameInputEnter = (event: React.KeyboardEvent) => { - if (event.key === 'Enter' && canAddMembers && inputRef.current) { - event.preventDefault(); - if (!billInfo.members.map(({name}) => name).includes(nameInput)) { - setBillInfoMemberWithId(nameInput); - setNameInput(''); - inputRef.current.value = ''; - inputRef.current.blur(); - setTimeout(() => { - if (inputRef.current) inputRef.current?.focus(); - }, 10); - } - } - }; - - const handlePostBill = async () => { - if (billInfo.members.map(({id}) => id).includes(-1)) { - const newMembers = await postMembersAsync({ - members: billInfo.members - .filter(({id}) => id === -1) - .map(({name}) => ({ - name, - })), - }); - postBill({ - title: billInfo.title, - price: Number(billInfo.price.replace(',', '')), - memberIds: billInfo.members.map(member => - member.id === -1 ? newMembers.members.find(m => m.name === member.name)?.id || member.id : member.id, - ), - }); - } else { - postBill({ - title: billInfo.title, - price: Number(billInfo.price.replace(',', '')), - memberIds: billInfo.members.map(({id}) => id), - }); - } - }; - - useEffect(() => { - if (isSuccessPostBill) { - navigate(`/event/${eventId}/admin`); - } - }, [isSuccessPostBill]); - - const handlePrevStep = () => { - setStep('title'); - }; - - return { - errorMessage, - nameInput, - inputRef, - handleNameInputChange, - handleNameInputEnter, - isPendingPostBill, - isPendingPostMembers, - canSubmitMembers, - handlePostBill, - handlePrevStep, - }; -}; - -export default useMembersStep; diff --git a/client/src/hooks/useNavSwitch.tsx b/client/src/hooks/useNavSwitch.tsx new file mode 100644 index 000000000..a622a7a30 --- /dev/null +++ b/client/src/hooks/useNavSwitch.tsx @@ -0,0 +1,42 @@ +import {useEffect, useState} from 'react'; +import {useLocation, useNavigate} from 'react-router-dom'; + +const PATH_TABLE: Record = { + ํ™ˆ: 'home', + ๊ด€๋ฆฌ: 'admin', +}; + +const PATH_DISPLAY_TABLE: Record = { + home: 'ํ™ˆ', + admin: '๊ด€๋ฆฌ', +}; + +const useNavSwitch = () => { + const paths = ['ํ™ˆ', '๊ด€๋ฆฌ']; + const location = useLocation(); + const navigate = useNavigate(); + + const pathArray = location.pathname.split('/'); + const basePath = pathArray.slice(0, -1).join('/'); + const lastPath = pathArray[pathArray.length - 1]; + + const [nav, setNav] = useState(PATH_DISPLAY_TABLE[lastPath]); + + useEffect(() => { + const isLogin = lastPath === 'login'; + setNav(isLogin ? '๊ด€๋ฆฌ' : PATH_DISPLAY_TABLE[lastPath]); + }, [location]); + + const onChange = (displayName: string) => { + setNav(displayName); + navigate(`${basePath}/${PATH_TABLE[displayName]}`); + }; + + return { + nav, + paths, + onChange, + }; +}; + +export default useNavSwitch; diff --git a/client/src/hooks/usePriceStep.ts b/client/src/hooks/usePriceStep.ts deleted file mode 100644 index 181a44f3d..000000000 --- a/client/src/hooks/usePriceStep.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {useCallback} from 'react'; - -import {BillInfo} from '@pages/AddBillFunnel/AddBillFunnel'; - -import {BillStep} from './useAddBillFunnel'; - -interface Props { - setStep: React.Dispatch>; - setBillInfo: React.Dispatch>; -} - -const usePriceStep = ({setStep, setBillInfo}: Props) => { - const handleNumberKeyboardChange = useCallback( - (value: string) => { - setBillInfo(prev => ({...prev, price: value})); - }, - [setBillInfo], - ); - - const handleNextStep = () => { - setStep('title'); - }; - - return {handleNumberKeyboardChange, handleNextStep}; -}; - -export default usePriceStep; diff --git a/client/src/hooks/usePutAndDeleteBill.ts b/client/src/hooks/usePutAndDeleteBill.ts deleted file mode 100644 index 60c0ea358..000000000 --- a/client/src/hooks/usePutAndDeleteBill.ts +++ /dev/null @@ -1,115 +0,0 @@ -// import type {Bill, BillInputType, InputPair} from 'types/serviceType'; - -// import {useEffect, useState} from 'react'; - -// import {ValidateResult} from '@utils/validate/type'; - -// import {ERROR_MESSAGE} from '@constants/errorMessage'; - -// import usePutBillAction from './queries/'; -// import useDeleteBillAction from './queries/useRequestDeleteBill'; - -// const usePutAndDeleteBill = ( -// initialValue: InputPair, -// validateFunc: (inputPair: Bill) => ValidateResult, -// onClose: () => void, -// ) => { -// const [inputPair, setInputPair] = useState(initialValue); -// const [canSubmit, setCanSubmit] = useState(false); -// const [errorInfo, setErrorInfo] = useState>({title: false, price: false}); -// const [errorMessage, setErrorMessage] = useState(null); - -// const {mutateAsync: putBillAction} = usePutBillAction(); -// const {mutate: deleteBillAction} = useDeleteBillAction(); - -// // ํ˜„์žฌ ํƒ€๊ฒŸ์˜ event.target.value๋ฅผ ๋„ฃ์–ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ -// const getFieldValue = (field: BillInputType, value: string) => { -// if (field === 'title') { -// return {title: value, price: Number(inputPair.price)}; -// } else { -// return {title: inputPair.title, price: Number(value)}; -// } -// }; - -// // TODO: (@weadie) getFieldValue ๋ฅผ ๋ฆฌํŽ™ํ† ๋งํ•ด์•ผํ•œ๋‹ค. - -// const handleInputChange = (field: BillInputType, event: React.ChangeEvent) => { -// const {value} = event.target; - -// if (value.length > 20) return; - -// const {isValid, errorMessage, errorInfo} = validateFunc(getFieldValue(field, value)); - -// setErrorMessage(errorMessage); - -// if (isValid) { -// // valid์ผ ๊ฒฝ์šฐ ์—๋Ÿฌ๋ฉ”์‹œ์ง€ nope, setValue, submit์€ value๊ฐ€ ๋น„์ง€ ์•Š์•˜์„ ๋•Œ true๋ฅผ ์„ค์ • -// setInputPair(prevInputPair => { -// return { -// ...prevInputPair, -// [field]: value, -// }; -// }); -// setCanSubmit(value.length !== 0); -// } else { -// const {isValid: isValidName} = validateFunc(getFieldValue('title', inputPair.title)); -// const {isValid: isValidPrice} = validateFunc(getFieldValue('price', inputPair.price)); - -// setCanSubmit(isValidName && isValidPrice); -// // validํ•˜์ง€ ์•Š์œผ๋ฉด event.target.value ๋ฎ์–ด์“ฐ๊ธฐ -// event.target.value = inputPair[field]; -// } - -// if (field === 'title') { -// // ํ˜„์žฌ field๊ฐ€ title์ผ ๋•Œ๋Š” title์˜ errorInfo๋งŒ ๋ฐ˜์˜ํ•ด์คŒ (blur์—์„œ๋„ errorInfo๋ฅผ ์กฐ์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ) -// setErrorInfo(prev => ({title: errorInfo?.title ?? false, price: prev.price})); -// } else { -// setErrorInfo(prev => ({title: prev.title, price: errorInfo?.price ?? false})); -// } -// }; - -// const handleOnBlur = () => { -// const {isValid, errorMessage, errorInfo} = validateFunc({title: inputPair.title, price: Number(inputPair.price)}); - -// // blur์‹œ ๊ฐ’์ด ๋น„์—ˆ์„ ๋•Œ error state ๋ฐ˜์˜ -// if (inputPair.price.length === 0 || inputPair.title.length === 0) { -// setErrorMessage(ERROR_MESSAGE.preventEmpty); -// setErrorInfo({title: inputPair.title.length === 0, price: inputPair.price.length === 0}); -// setCanSubmit(false); -// return; -// } - -// // ์ด์™ธ blur์‹œ์— ์ถ”๊ฐ€๋กœ ๊ฒ€์ฆํ•จ -// setErrorMessage(errorMessage); -// setCanSubmit(isValid); -// setErrorInfo(errorInfo ?? {title: false, price: false}); -// }; - -// const onSubmit = async (event: React.FormEvent, inputPair: InputPair, actionId: number) => { -// event.preventDefault(); - -// const {title, price} = inputPair; - -// await putBillAction({actionId, title, price: Number(price)}); - -// onClose(); -// }; - -// const onDelete = async (actionId: number) => { -// deleteBillAction({actionId}); -// onClose(); -// }; - -// return { -// inputPair, -// handleInputChange, -// handleOnBlur, -// onSubmit, -// onDelete, -// canSubmit, -// errorMessage, -// errorInfo, -// }; -// }; - -// export default usePutAndDeleteBill; diff --git a/client/src/hooks/usePutAndDeleteBillAction.ts b/client/src/hooks/usePutAndDeleteBillAction.ts new file mode 100644 index 000000000..6f1e4feaf --- /dev/null +++ b/client/src/hooks/usePutAndDeleteBillAction.ts @@ -0,0 +1,113 @@ +import type {Bill, BillInputType, InputPair} from 'types/serviceType'; + +import {useEffect, useState} from 'react'; + +import {ValidateResult} from '@utils/validate/type'; + +import {ERROR_MESSAGE} from '@constants/errorMessage'; + +import usePutBillAction from './queries/useRequestPutBillAction'; +import useDeleteBillAction from './queries/useRequestDeleteBillAction'; + +const usePutAndDeleteBillAction = ( + initialValue: InputPair, + validateFunc: (inputPair: Bill) => ValidateResult, + onClose: () => void, +) => { + const [inputPair, setInputPair] = useState(initialValue); + const [canSubmit, setCanSubmit] = useState(false); + const [errorInfo, setErrorInfo] = useState>({title: false, price: false}); + const [errorMessage, setErrorMessage] = useState(null); + + const {mutateAsync: putBillAction} = usePutBillAction(); + const {mutate: deleteBillAction} = useDeleteBillAction(); + + // ํ˜„์žฌ ํƒ€๊ฒŸ์˜ event.target.value๋ฅผ ๋„ฃ์–ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ + const getFieldValue = (field: BillInputType, value: string) => { + if (field === 'title') { + return {title: value, price: Number(inputPair.price)}; + } else { + return {title: inputPair.title, price: Number(value)}; + } + }; + + // TODO: (@weadie) getFieldValue ๋ฅผ ๋ฆฌํŽ™ํ† ๋งํ•ด์•ผํ•œ๋‹ค. + + const handleInputChange = (field: BillInputType, event: React.ChangeEvent) => { + const {value} = event.target; + + const {isValid, errorMessage, errorInfo} = validateFunc(getFieldValue(field, value)); + + setErrorMessage(errorMessage); + + if (isValid) { + // valid์ผ ๊ฒฝ์šฐ ์—๋Ÿฌ๋ฉ”์‹œ์ง€ nope, setValue, submit์€ value๊ฐ€ ๋น„์ง€ ์•Š์•˜์„ ๋•Œ true๋ฅผ ์„ค์ • + setInputPair(prevInputPair => { + return { + ...prevInputPair, + [field]: value, + }; + }); + setCanSubmit(value.length !== 0); + } else { + const {isValid: isValidName} = validateFunc(getFieldValue('title', inputPair.title)); + const {isValid: isValidPrice} = validateFunc(getFieldValue('price', inputPair.price)); + + setCanSubmit(isValidName && isValidPrice); + // validํ•˜์ง€ ์•Š์œผ๋ฉด event.target.value ๋ฎ์–ด์“ฐ๊ธฐ + event.target.value = inputPair[field]; + } + + if (field === 'title') { + // ํ˜„์žฌ field๊ฐ€ title์ผ ๋•Œ๋Š” title์˜ errorInfo๋งŒ ๋ฐ˜์˜ํ•ด์คŒ (blur์—์„œ๋„ errorInfo๋ฅผ ์กฐ์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ) + setErrorInfo(prev => ({title: errorInfo?.title ?? false, price: prev.price})); + } else { + setErrorInfo(prev => ({title: prev.title, price: errorInfo?.price ?? false})); + } + }; + + const handleOnBlur = () => { + const {isValid, errorMessage, errorInfo} = validateFunc({title: inputPair.title, price: Number(inputPair.price)}); + + // blur์‹œ ๊ฐ’์ด ๋น„์—ˆ์„ ๋•Œ error state ๋ฐ˜์˜ + if (inputPair.price.length === 0 || inputPair.title.length === 0) { + setErrorMessage(ERROR_MESSAGE.preventEmpty); + setErrorInfo({title: inputPair.title.length === 0, price: inputPair.price.length === 0}); + setCanSubmit(false); + return; + } + + // ์ด์™ธ blur์‹œ์— ์ถ”๊ฐ€๋กœ ๊ฒ€์ฆํ•จ + setErrorMessage(errorMessage); + setCanSubmit(isValid); + setErrorInfo(errorInfo ?? {title: false, price: false}); + }; + + const onSubmit = async (event: React.FormEvent, inputPair: InputPair, actionId: number) => { + event.preventDefault(); + + const {title, price} = inputPair; + + await putBillAction({actionId, title, price: Number(price)}); + + onClose(); + }; + + const onDelete = async (actionId: number) => { + deleteBillAction({actionId}); + onClose(); + }; + + return { + inputPair, + handleInputChange, + handleOnBlur, + onSubmit, + onDelete, + canSubmit, + errorMessage, + errorInfo, + }; +}; + +export default usePutAndDeleteBillAction; diff --git a/client/src/hooks/useReportsPage.ts b/client/src/hooks/useReportsPage.ts deleted file mode 100644 index 87ab2c59f..000000000 --- a/client/src/hooks/useReportsPage.ts +++ /dev/null @@ -1,60 +0,0 @@ -import {useState} from 'react'; -import {useOutletContext} from 'react-router-dom'; - -import {EventPageContextProps} from '@pages/EventPage/EventPageLayout'; - -import {isAndroid, isIOS} from '@utils/detectDevice'; - -import {ERROR_MESSAGE} from '@constants/errorMessage'; - -import {useSearchReports} from './useSearchReports'; -import toast from './useToast/toast'; - -const useReportsPage = () => { - const [memberName, setMemberName] = useState(''); - const {bankName, accountNumber} = useOutletContext(); - const {matchedReports, reports} = useSearchReports({memberName}); - - const changeName = ({target}: React.ChangeEvent) => { - setMemberName(target.value); - }; - - const onBankButtonClick = () => { - if (bankName.trim() === '' || accountNumber.trim() === '') { - toast.error(ERROR_MESSAGE.emptyBank, { - showingTime: 3000, - position: 'bottom', - }); - return; - } - - if (isAndroid()) { - const url = 'supertoss://'; - window.location.href = url; - return; - } - - if (isIOS()) { - const url = 'supertoss://send'; - window.location.href = url; - return; - } - }; - - const expenseListProp = matchedReports.map(member => ({ - ...member, - clipboardText: `${bankName} ${accountNumber} ${member.price}์›`, - onBankButtonClick, - })); - - const isEmpty = reports.length <= 0; - - return { - isEmpty, - expenseListProp, - memberName, - changeName, - }; -}; - -export default useReportsPage; diff --git a/client/src/hooks/useSearchInMemberList.ts b/client/src/hooks/useSearchInMemberList.ts new file mode 100644 index 000000000..09f227b8e --- /dev/null +++ b/client/src/hooks/useSearchInMemberList.ts @@ -0,0 +1,54 @@ +import {useState} from 'react'; + +import useRequestGetCurrentInMemberList from './queries/useRequestGetCurrentInMemberList'; + +export type ReturnUseSearchInMemberList = { + currentInputIndex: number; + handleCurrentInputIndex: (inputIndex: number) => void; + filteredInMemberList: string[]; + searchCurrentInMember: (event: React.ChangeEvent) => void; + chooseMember: (inputIndex: number, name: string) => void; +}; + +const useSearchInMemberList = (handleChange: (index: number, value: string) => void): ReturnUseSearchInMemberList => { + const [currentInputIndex, setCurrentInputIndex] = useState(-1); + + // ์„œ๋ฒ„์—์„œ ๊ฐ€์ ธ์˜จ ์ „์ฒด ๋ฆฌ์ŠคํŠธ + const {data} = useRequestGetCurrentInMemberList(); + const currentInMemberList = data?.memberNames ?? []; + + // ๊ฒ€์ƒ‰๋œ ๋ฆฌ์ŠคํŠธ (๋”ฐ๋กœ ๋‘” ์ด์œ ๋Š” ๊ฒ€์ƒ‰ ํ›„ ํด๋ฆญํ–ˆ์„ ๋•Œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋น„์›Œ์ฃผ์–ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ) + const [filteredInMemberList, setFilteredInMemberList] = useState>([]); + + const filterMatchItems = (keyword: string) => { + if (keyword.trim() === '') return []; + + return currentInMemberList + .filter(member => member.toLocaleLowerCase().indexOf(keyword.toLocaleLowerCase()) > -1) + .slice(0, 3); + }; + + const chooseMember = (inputIndex: number, name: string) => { + setFilteredInMemberList([]); + handleChange(inputIndex, name); + }; + + const searchCurrentInMember = (event: React.ChangeEvent) => { + const {value} = event.target; + setFilteredInMemberList(filterMatchItems(value)); + }; + + const handleCurrentInputIndex = (inputIndex: number) => { + setCurrentInputIndex(inputIndex); + }; + + return { + currentInputIndex, + handleCurrentInputIndex, + filteredInMemberList, + searchCurrentInMember, + chooseMember, + }; +}; + +export default useSearchInMemberList; diff --git a/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.test.tsx b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.test.tsx new file mode 100644 index 000000000..90782cbdf --- /dev/null +++ b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.test.tsx @@ -0,0 +1,41 @@ +import {renderHook, waitFor} from '@testing-library/react'; +import {MemoryRouter} from 'react-router-dom'; + +import AppErrorBoundary from '@components/AppErrorBoundary/ErrorCatcher'; +import QueryClientBoundary from '@components/QueryClientBoundary/QueryClientBoundary'; +import {ToastProvider} from '@hooks/useToast/ToastProvider'; + +import reportListJson from '../../mocks/reportList.json'; + +import useSearchMemberReportList from './useSearchMemberReportList'; + +describe('useSearchMemberReportList', () => { + const initializeProvider = (name: string) => + renderHook(() => useSearchMemberReportList({name}), { + wrapper: ({children}) => ( + + + + {children} + + + + ), + }); + + it('๋นˆ ๊ฐ’์„ ๊ฒ€์ƒ‰ํ•œ๋‹ค๋ฉด ๊ฒ€์ƒ‰ ๋ชฉ๋ก์€ ๋น„์–ด์žˆ๋‹ค.', async () => { + const {result} = initializeProvider(''); + + await waitFor(() => expect(result.current.memberReportSearchList).toStrictEqual(reportListJson)); + }); + + it('๊ฒ€์ƒ‰์–ด์˜ ์ผ๋ถ€์™€ ์ผ์น˜ํ•˜๋Š” ์ด๋ฆ„์ด ์žˆ๋‹ค๋ฉด ํ•ด๋‹น ์ด๋ฆ„์„ ๋ชฉ๋ก์— ๋ฐ˜ํ™˜ํ•œ๋‹ค.', async () => { + const keyword = '์†Œ'; + const {result} = initializeProvider(keyword); + const expectedMemberReportSearchList = reportListJson.filter(memberReport => memberReport.name.includes(keyword)); + + await waitFor(() => { + expect(result.current.memberReportSearchList).toStrictEqual(expectedMemberReportSearchList); + }); + }); +}); diff --git a/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx new file mode 100644 index 000000000..4a967e45c --- /dev/null +++ b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx @@ -0,0 +1,16 @@ +import useRequestGetMemberReportList from '@hooks/queries/useRequestGetMemberReportList'; + +type UseSearchMemberReportListParams = { + name: string; +}; + +const useSearchMemberReportList = ({name}: UseSearchMemberReportListParams) => { + const {data} = useRequestGetMemberReportList(); + const memberReportList = data ?? []; + + return { + memberReportSearchList: memberReportList.filter(memberReport => memberReport.name.includes(name)), + }; +}; + +export default useSearchMemberReportList; diff --git a/client/src/hooks/useSearchReports/index.ts b/client/src/hooks/useSearchReports/index.ts deleted file mode 100644 index 619af5493..000000000 --- a/client/src/hooks/useSearchReports/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default as useSearchReports} from './useSearchReports'; diff --git a/client/src/hooks/useSearchReports/useSearchReports.tsx b/client/src/hooks/useSearchReports/useSearchReports.tsx deleted file mode 100644 index 25ce95cca..000000000 --- a/client/src/hooks/useSearchReports/useSearchReports.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import useRequestGetReports from '@hooks/queries/report/useRequestGetReports'; - -type UseSearchReportsParams = { - memberName: string; -}; - -const useSearchReports = ({memberName}: UseSearchReportsParams) => { - const {reports} = useRequestGetReports(); - - return { - matchedReports: reports.filter(memberReport => memberReport.memberName.includes(memberName)), - reports, - }; -}; - -export default useSearchReports; diff --git a/client/src/hooks/useSetAllMemberList.tsx b/client/src/hooks/useSetAllMemberList.tsx new file mode 100644 index 000000000..02241d3e3 --- /dev/null +++ b/client/src/hooks/useSetAllMemberList.tsx @@ -0,0 +1,100 @@ +import {useEffect, useState} from 'react'; + +import {ValidateResult} from '@utils/validate/type'; +import {MemberChange} from '@apis/request/member'; + +import isArraysEqual from '@utils/isArraysEqual'; + +import useDeleteAllMemberList from './queries/useRequestDeleteAllMemberList'; +import usePutAllMemberList from './queries/useRequestPutAllMemberList'; +import useInput from './useInput'; + +interface UseSetAllMemberListProps { + validateFunc: (name: string) => ValidateResult; + allMemberList: string[]; + handleCloseAllMemberListModal: () => void; +} + +interface UseSetAllMemberListReturns { + editedAllMemberList: string[]; + canSubmit: boolean; + errorMessage: string; + errorIndexList: number[]; + handleNameChange: (index: number, event: React.ChangeEvent) => void; + handleClickDeleteButton: (index: number) => Promise; + handlePutAllMemberList: () => Promise; +} + +const useSetAllMemberList = ({ + validateFunc, + allMemberList, + handleCloseAllMemberListModal, +}: UseSetAllMemberListProps): UseSetAllMemberListReturns => { + const initialInputList = allMemberList.map((name, index) => ({index, value: name})); + const { + inputList, + errorMessage, + errorIndexList, + canSubmit, + handleChange, + setInputList: setEditedAllMemberList, + setCanSubmit, + } = useInput({validateFunc, initialInputList}); + + const [deleteInOriginal, setDeleteInOriginal] = useState(allMemberList); + const [deleteMemberList, setDeleteMemberList] = useState([]); + + const {mutateAsync: deleteAllMemberList} = useDeleteAllMemberList(); + const {mutate: putAllMemberList} = usePutAllMemberList(); + + const editedAllMemberList = inputList.map(input => input.value); + + useEffect(() => { + setCanSubmit(!isArraysEqual(editedAllMemberList, allMemberList)); + }, [editedAllMemberList]); + + const handleNameChange = (index: number, event: React.ChangeEvent) => { + const {value} = event.target; + + handleChange(index, value); + }; + + const handleClickDeleteButton = async (index: number) => { + const memberToDelete = editedAllMemberList[index]; + + setDeleteMemberList(prev => [...prev, memberToDelete]); + setDeleteInOriginal(prev => [...prev.slice(0, index), ...prev.slice(index + 1)]); + setEditedAllMemberList(prev => [...prev.slice(0, index), ...prev.slice(index + 1)]); + }; + + const handlePutAllMemberList = async () => { + // deleteMemberList๊ฐ€ ๋น„์–ด์žˆ์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋งŒ ๋ฐ˜๋ณต๋ฌธ ์‹คํ–‰ (์‚ญ์ œ api ์š”์ฒญ) + if (deleteMemberList.length > 0) { + for (const deleteMember of deleteMemberList) { + await deleteAllMemberList({memberName: deleteMember}); + } + } + + const editedMemberName: MemberChange[] = deleteInOriginal + .map((originalName, index) => { + if (editedAllMemberList[index] !== originalName) { + return {before: originalName, after: editedAllMemberList[index]}; + } + return null; // ์กฐ๊ฑด์— ๋งž์ง€ ์•Š์œผ๋ฉด null์„ ๋ฐ˜ํ™˜ + }) + .filter(item => item !== null); // null์ธ ํ•ญ๋ชฉ์„ ํ•„ํ„ฐ๋งํ•˜์—ฌ ์ œ๊ฑฐ + if (!isArraysEqual(editedAllMemberList, deleteInOriginal)) putAllMemberList({members: editedMemberName}); + handleCloseAllMemberListModal(); + }; + + return { + editedAllMemberList, + canSubmit, + errorMessage, + errorIndexList, + handleNameChange, + handleClickDeleteButton, + handlePutAllMemberList, + }; +}; +export default useSetAllMemberList; diff --git a/client/src/hooks/useSetBillInput.ts b/client/src/hooks/useSetBillInput.ts new file mode 100644 index 000000000..a14b2a481 --- /dev/null +++ b/client/src/hooks/useSetBillInput.ts @@ -0,0 +1,67 @@ +import {useState} from 'react'; + +import validatePurchase from '@utils/validate/validatePurchase'; +import {Bill, BillInputType} from 'types/serviceType'; + +import useRequestPostBillList from './queries/useRequestPostBillList'; + +interface UseSetBillInputProps { + setIsAddEditableItem: React.Dispatch>; +} + +interface UseSetBillInputReturns { + billInput: Bill; + handleChangeBillInput: (field: BillInputType, event: React.ChangeEvent) => void; + handleBlurBillRequest: () => void; +} + +const useSetBillInput = ({setIsAddEditableItem}: UseSetBillInputProps): UseSetBillInputReturns => { + const initialInput = {title: '', price: 0}; + const [billInput, setBillInput] = useState(initialInput); + + const {mutate: postBillList} = useRequestPostBillList(); + + const handleChangeBillInput = (field: BillInputType, event: React.ChangeEvent) => { + const {value} = event.target; + const {isValid} = validatePurchase({ + ...billInput, + [field]: value, + }); + + if (isValid) { + setBillInput(prev => ({ + ...prev, + [field]: value, + })); + } + }; + + const handleBlurBillRequest = () => { + const isEmptyTitle = billInput.title.trim().length; + const isEmptyPrice = Number(billInput.price); + + // ๋‘ input์˜ ๊ฐ’์ด ๋ชจ๋‘ ์ฑ„์›Œ์กŒ์„ ๋•Œ api ์š”์ฒญ + // api ์š”์ฒญ์„ ํ•˜๋ฉด Input์„ ๋„์šฐ์ง€ ์•Š์Œ + if (isEmptyTitle && isEmptyPrice) { + postBillList( + {billList: [billInput]}, + { + onSuccess: () => { + setBillInput(initialInput); + setIsAddEditableItem(false); + }, + }, + ); + } else if (!isEmptyTitle && !isEmptyPrice) { + setIsAddEditableItem(false); + } + }; + + return { + billInput, + handleBlurBillRequest, + handleChangeBillInput, + }; +}; + +export default useSetBillInput; diff --git a/client/src/hooks/useSetEventNameStep.ts b/client/src/hooks/useSetEventNamePage.ts similarity index 71% rename from client/src/hooks/useSetEventNameStep.ts rename to client/src/hooks/useSetEventNamePage.ts index ae087434d..f5b5bce12 100644 --- a/client/src/hooks/useSetEventNameStep.ts +++ b/client/src/hooks/useSetEventNamePage.ts @@ -2,9 +2,7 @@ import {useState} from 'react'; import validateEventName from '@utils/validate/validateEventName'; -export type UseSetEventNameStepReturnType = ReturnType; - -const useSetEventNameStep = () => { +const useSetEventNamePage = () => { const [eventName, setEventName] = useState(''); const [errorMessage, setErrorMessage] = useState(null); const [canSubmit, setCanSubmit] = useState(false); @@ -13,13 +11,14 @@ const useSetEventNameStep = () => { const newValue = event.target.value; const validation = validateEventName(newValue); - if (!validation.isValid) { - setErrorMessage(validation.errorMessage); - } else { - setErrorMessage(''); + setCanSubmit(newValue.length !== 0); + setErrorMessage(validation.errorMessage); + + if (validation.isValid) { setEventName(newValue); + } else { + event.target.value = eventName; } - setCanSubmit(newValue.length !== 0); }; return { @@ -30,4 +29,4 @@ const useSetEventNameStep = () => { }; }; -export default useSetEventNameStep; +export default useSetEventNamePage; diff --git a/client/src/hooks/useSetEventPasswordPage.ts b/client/src/hooks/useSetEventPasswordPage.ts new file mode 100644 index 000000000..82ca72fb1 --- /dev/null +++ b/client/src/hooks/useSetEventPasswordPage.ts @@ -0,0 +1,60 @@ +import {useEffect, useState} from 'react'; +import {useLocation, useNavigate} from 'react-router-dom'; + +import validateEventPassword from '@utils/validate/validateEventPassword'; + +import {ROUTER_URLS} from '@constants/routerUrls'; +import RULE from '@constants/rule'; + +import usePostEvent from './queries/useRequestPostEvent'; + +const useSetEventPasswordPage = () => { + const [eventName, setEventName] = useState(''); + const [password, setPassword] = useState(''); + const [errorMessage, setErrorMessage] = useState(''); + const [canSubmit, setCanSubmit] = useState(false); + const navigate = useNavigate(); + const location = useLocation(); + const {mutate: postEvent, isPending: isPostEventPending} = usePostEvent(); + + useEffect(() => { + if (!location.state) { + navigate(ROUTER_URLS.main); + } else { + setEventName(location.state.eventName); + } + }, []); + + const submitPassword = async (event: React.FormEvent) => { + event.preventDefault(); + + postEvent( + {eventName, password: parseInt(password)}, + { + onSuccess: data => { + navigate(`${ROUTER_URLS.eventCreateComplete}?${new URLSearchParams({eventId: data.eventId})}`, { + replace: true, + }); + }, + }, + ); + }; + + const handleChange = (event: React.ChangeEvent) => { + const newValue = event.target.value; + const validation = validateEventPassword(newValue); + + setCanSubmit(newValue.length === RULE.maxEventPasswordLength); + + if (validation.isValid) { + setPassword(newValue); + setErrorMessage(''); + } else { + event.target.value = password; + setErrorMessage(validation.errorMessage ?? ''); + } + }; + + return {submitPassword, errorMessage, password, handleChange, canSubmit, isPostEventPending}; +}; +export default useSetEventPasswordPage; diff --git a/client/src/hooks/useSetEventPasswordStep.ts b/client/src/hooks/useSetEventPasswordStep.ts deleted file mode 100644 index 5705be855..000000000 --- a/client/src/hooks/useSetEventPasswordStep.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {useState} from 'react'; -import {useNavigate} from 'react-router-dom'; - -import validateEventPassword from '@utils/validate/validateEventPassword'; - -import RULE from '@constants/rule'; - -import useRequestPostEvent from './queries/event/useRequestPostEvent'; - -export type UseSetEventPasswordStepReturnType = ReturnType; - -const useSetEventPasswordStep = () => { - const [password, setPassword] = useState(''); - const [errorMessage, setErrorMessage] = useState(''); - const [canSubmit, setCanSubmit] = useState(false); - const {postEvent: requestPostEvent, isPostEventPending} = useRequestPostEvent(); - - const submitDataForPostEvent = async ({ - event, - eventName, - setEventToken, - }: { - event: React.FormEvent; - eventName: string; - setEventToken: (eventToken: string) => void; - }) => { - event.preventDefault(); - - await postEvent(eventName, setEventToken); - }; - - const getPasswordWithPad = () => { - return String(password).padStart(4, '0'); - }; - - const postEvent = async (eventName: string, updateEventToken: (eventToken: string) => void) => { - await requestPostEvent( - {eventName, password: getPasswordWithPad()}, - { - onSuccess: ({eventId}) => { - updateEventToken(eventId); - }, - }, - ); - }; - - const handleChange = (event: React.ChangeEvent) => { - const newValue = event.target.value; - const validation = validateEventPassword(newValue); - - setCanSubmit(newValue.length === RULE.maxEventPasswordLength); - - if (validation.isValid) { - setPassword(newValue); - setErrorMessage(''); - } else { - event.target.value = password; - setErrorMessage(validation.errorMessage ?? ''); - } - }; - - return { - submitDataForPostEvent, - errorMessage, - handleChange, - canSubmit, - isPostEventPending, - password, - }; -}; - -export default useSetEventPasswordStep; diff --git a/client/src/hooks/useShareEvent.ts b/client/src/hooks/useShareEvent.ts deleted file mode 100644 index 86d185f48..000000000 --- a/client/src/hooks/useShareEvent.ts +++ /dev/null @@ -1,47 +0,0 @@ -import getEventIdByUrl from '@utils/getEventIdByUrl'; -import getEventPageUrlByEnvironment from '@utils/getEventPageUrlByEnvironment'; - -const useShareEvent = (eventName: string, isMobile: boolean) => { - const eventId = getEventIdByUrl(); - const url = getEventPageUrlByEnvironment(eventId, 'home'); - - const shareInfo = { - title: `[ํ–‰๋™๋Œ€์žฅ]\n${eventName}์— ๋Œ€ํ•œ ์ •์‚ฐ์„ ์‹œ์ž‘ํ• ๊ฒŒ์š”:)`, - text: '์•„๋ž˜ ๋งํฌ์— ์ ‘์†ํ•ด์„œ ์ •์‚ฐ ๋‚ด์—ญ์„ ํ™•์ธํ•ด ์ฃผ์„ธ์š”!', - url, - }; - - // ๋ชจ๋ฐ”์ผ์ด ์•„๋‹Œ ๊ธฐ๊ธฐ๋Š” ๋‹จ์ˆœ ํ…์ŠคํŠธ ๋ณต์‚ฌ - // ๋ชจ๋ฐ”์ผ ๊ธฐ๊ธฐ์—์„œ๋Š” ์นด์นด์˜คํ†ก ๊ณต์œ ๋ฅผ ์‚ฌ์šฉ - const onShareButtonClick = () => { - if (!isMobile) return; - - kakaoShare(); - }; - - const kakaoShare = () => { - window.Kakao.Share.sendDefault({ - objectType: 'feed', - content: { - title: shareInfo.title, - description: shareInfo.text, - imageUrl: - 'https://wooteco-crew-wiki.s3.ap-northeast-2.amazonaws.com/%EC%9B%A8%EB%94%94%286%EA%B8%B0%29/g583lirp8yg.jpg', - link: { - mobileWebUrl: url, - webUrl: url, - }, - }, - buttonTitle: '์ •์‚ฐ ํ™•์ธํ•˜๊ธฐ', - }); - }; - - const shareText = `${shareInfo.title}\n${shareInfo.text}\n${url}`; - - return { - shareText, - onShareButtonClick, - }; -}; - -export default useShareEvent; diff --git a/client/src/hooks/useTitleStep.ts b/client/src/hooks/useTitleStep.ts deleted file mode 100644 index 8ed5c787c..000000000 --- a/client/src/hooks/useTitleStep.ts +++ /dev/null @@ -1,64 +0,0 @@ -import {useState} from 'react'; - -import {BillInfo} from '@pages/AddBillFunnel/AddBillFunnel'; - -import REGEXP from '@constants/regExp'; - -import {BillStep} from './useAddBillFunnel'; - -interface Props { - billInfo: BillInfo; - setBillInfo: React.Dispatch>; - setStep: React.Dispatch>; -} - -const useTitleStep = ({billInfo, setBillInfo, setStep}: Props) => { - const [errorMessage, setErrorMessage] = useState(''); - - const onTitleInputChange = (value: string) => { - if (REGEXP.billTitle.test(value)) { - setBillInfo(prev => ({...prev, title: value})); - } - }; - - const handleTitleInputChange = (event: React.ChangeEvent) => { - if (event.target.value.length > 12) { - setErrorMessage('์ง€์ถœ๋‚ด์—ญ์€ 12์ž๊นŒ์ง€ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ด์š”'); - onTitleInputChange(billInfo.title.slice(0, 12)); - } else { - setErrorMessage(''); - onTitleInputChange(event.target.value); - } - }; - - const canSubmitTitleInput = billInfo.title && !errorMessage; - - const handleTitleInputEnter = (event: React.KeyboardEvent) => { - if (event.nativeEvent.isComposing) { - return; - } - if (event.key === 'Enter' && canSubmitTitleInput) { - event.preventDefault(); - setStep('members'); - } - }; - - const handleNextStep = () => { - setStep('members'); - }; - - const handlePrevStep = () => { - setStep('price'); - }; - - return { - errorMessage, - handleTitleInputChange, - handleTitleInputEnter, - canSubmitTitleInput, - handleNextStep, - handlePrevStep, - }; -}; - -export default useTitleStep; diff --git a/client/src/hooks/useToast/ToastProvider.tsx b/client/src/hooks/useToast/ToastProvider.tsx new file mode 100644 index 000000000..be0d2ea15 --- /dev/null +++ b/client/src/hooks/useToast/ToastProvider.tsx @@ -0,0 +1,47 @@ +/** @jsxImportSource @emotion/react */ +import {createContext, useEffect, useState} from 'react'; + +import {ToastProps} from '../../components/Toast/Toast.type'; +import Toast from '../../components/Toast/Toast'; + +export const ToastContext = createContext(null); + +const DEFAULT_TIME = 3000; + +interface ToastContextProps { + showToast: (args: ShowToast) => void; +} + +type ShowToast = ToastProps & { + showingTime?: number; + isAlwaysOn?: boolean; +}; + +export const ToastProvider = ({children}: React.PropsWithChildren) => { + const [currentToast, setCurrentToast] = useState(null); + + const showToast = ({showingTime = DEFAULT_TIME, isAlwaysOn = false, ...toastProps}: ShowToast) => { + setCurrentToast({showingTime, isAlwaysOn, ...toastProps}); + }; + + const closeToast = () => { + setCurrentToast(null); + }; + + useEffect(() => { + if (currentToast && !currentToast.isAlwaysOn) { + const timer = setTimeout(() => setCurrentToast(null), currentToast.showingTime); + + return () => clearTimeout(timer); + } + + return; + }, [currentToast]); + + return ( + + {currentToast && } + {children} + + ); +}; diff --git a/client/src/hooks/useToast/toast.ts b/client/src/hooks/useToast/toast.ts deleted file mode 100644 index 362227a62..000000000 --- a/client/src/hooks/useToast/toast.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {ToastMessage, ToastOptions} from 'types/toastType'; - -import toastEventManager from './toastEventManager'; -import {TOAST_EVENT} from './toastEventManager.type'; - -const showToast = (message: ToastMessage, options: ToastOptions) => { - return toastEventManager.trigger(TOAST_EVENT.show, message, options); -}; - -// toast('์•ˆ๋…•') ์ฒ˜๋Ÿผ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก -const toast = (message: ToastMessage, options: ToastOptions = {}) => { - return showToast(message, options); -}; - -toast.error = (message: ToastMessage, options: ToastOptions = {}) => showToast(message, options); -toast.confirm = (message: ToastMessage, options: ToastOptions = {}) => showToast(message, options); -toast.none = (message: ToastMessage, options: ToastOptions = {}) => showToast(message, options); - -export default toast; diff --git a/client/src/hooks/useToast/toastEventManager.ts b/client/src/hooks/useToast/toastEventManager.ts deleted file mode 100644 index fc70d5af3..000000000 --- a/client/src/hooks/useToast/toastEventManager.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {AddEventHandlerArgs, ToastEventCallbackMap} from './toastEventManager.type'; - -const toastEventManager = (() => { - const eventCallbackList = new Map(); - - return { - // eventType์€ ToastEventCallbackMap ์ค‘ ํ•˜๋‚˜์˜ ๊ฐ’์„ ๋ฐ›๊ณ  ์ด ๊ฐ’์— ๋”ฐ๋ผ callbackํƒ€์ž…์ด ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค. - // ๋ชจํ‹ฐ๋ธŒ๋Š” addEventListener์œผ๋กœ.. listener ์ธ์ž์— ์ ์šฉ๋˜๋Š” ํƒ€์ž… narrowing๋ฐฉ๋ฒ•์„ ํ‰๋‚ด๋‚ธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. - addEventHandler({eventType, callback}: AddEventHandlerArgs) { - eventCallbackList.set(eventType, callback); - }, - - trigger(eventType: K, ...args: any) { - if (!eventCallbackList.has(eventType)) { - throw new Error(`ํ† ์ŠคํŠธ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์— ๋“ฑ๋ก๋œ ${eventType} ์ด๋ฒคํŠธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ ๋“ฑ๋ก ํ›„ ํ˜ธ์ถœํ•ด์ฃผ์„ธ์š”.`); - } - - const callback = eventCallbackList.get(eventType); - callback(...args); - }, - }; -})(); - -export default toastEventManager; diff --git a/client/src/hooks/useToast/toastEventManager.type.ts b/client/src/hooks/useToast/toastEventManager.type.ts deleted file mode 100644 index 0d7603983..000000000 --- a/client/src/hooks/useToast/toastEventManager.type.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {ToastMessage, ToastOptions} from 'types/toastType'; - -const TOAST_SHOW = 'TOAST_SHOW' as const; -const TOAST_CLOSE = 'TOAST_CLOSE' as const; - -export const TOAST_EVENT = { - show: TOAST_SHOW, - close: TOAST_CLOSE, -}; - -export type ToastEventType = typeof TOAST_SHOW | typeof TOAST_CLOSE; - -export type ToastEventCallbackMap = { - [TOAST_SHOW]: (message: ToastMessage, options: ToastOptions) => void; - [TOAST_CLOSE]: () => void; -}; - -export type AddEventHandlerArgs = { - eventType: K; - callback: ToastEventCallbackMap[K]; -}; diff --git a/client/src/hooks/useToast/useToast.test.tsx b/client/src/hooks/useToast/useToast.test.tsx index e8c1bdd3d..f790ba98e 100644 --- a/client/src/hooks/useToast/useToast.test.tsx +++ b/client/src/hooks/useToast/useToast.test.tsx @@ -1,19 +1,20 @@ import {render, renderHook, screen, waitFor} from '@testing-library/react'; import {act} from 'react'; +import {HDesignProvider} from 'haengdong-design'; -import ToastContainer from '@components/Toast/ToastContainer'; - -import {HDesignProvider} from '@HDesign/index'; - +import {ToastProvider} from './ToastProvider'; // ์œ„ ์ฝ”๋“œ์— ํ•ด๋‹นํ•˜๋Š” ToastProvider ๊ฒฝ๋กœ import {useToast} from './useToast'; -import toast from './toast'; -const TOAST_MESSAGE = 'ํ…Œ์ŠคํŠธ ๋ฉ”์„ธ์ง€์—์š”.'; +const TOAST_CONFIG = { + message: 'Test Toast Message', +}; // ํ…Œ์ŠคํŠธ์šฉ ํ—ฌํผ ์ปดํฌ๋„ŒํŠธ const TestComponent = () => { + const {showToast} = useToast(); + const handleClick = () => { - toast(TOAST_MESSAGE); + showToast(TOAST_CONFIG); }; return ; @@ -22,8 +23,9 @@ const TestComponent = () => { const setup = () => render( - - + + + , ); @@ -37,18 +39,18 @@ describe('ToastProvider', () => { }); // ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€๊ฐ€ ๋‚˜ํƒ€๋‚˜๋Š”์ง€ ํ™•์ธ - expect(screen.getByText(TOAST_MESSAGE)).toBeInTheDocument(); + expect(screen.getByText(TOAST_CONFIG.message)).toBeInTheDocument(); // 1์ดˆ ํ›„์— ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€๊ฐ€ ์‚ฌ๋ผ์ง€๋Š”์ง€ ํ™•์ธ await waitFor( () => { - expect(screen.queryByText(TOAST_MESSAGE)).not.toBeInTheDocument(); + expect(screen.queryByText(TOAST_CONFIG.message)).not.toBeInTheDocument(); }, {timeout: 3100}, ); // ํƒ€์ž„์•„์›ƒ์„ 3100ms๋กœ ์„ค์ •ํ•˜์—ฌ ์ •ํ™•ํžˆ 3์ดˆ ํ›„ ํ™•์ธ }); - it('ํ† ์ŠคํŠธ๋ฅผ ๋ˆ„๋ฅด๋ฉด ์‚ฌ๋ผ์ง„๋‹ค', async () => { + it('ํ† ์ŠคํŠธ ๋‹ซ๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ์‚ฌ๋ผ์ง„๋‹ค', async () => { setup(); // ํ† ์ŠคํŠธ๋ฅผ ๋„์šฐ๊ธฐ ์œ„ํ•ด ๋ฒ„ํŠผ ํด๋ฆญ @@ -57,7 +59,7 @@ describe('ToastProvider', () => { }); // ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€๊ฐ€ ๋‚˜ํƒ€๋‚˜๋Š”์ง€ ํ™•์ธ - expect(screen.getByText(TOAST_MESSAGE)).toBeInTheDocument(); + expect(screen.getByText(TOAST_CONFIG.message)).toBeInTheDocument(); // ํ† ์ŠคํŠธ์˜ ๋‹ซ๊ธฐ ๋ฒ„ํŠผ์„ ํด๋ฆญ act(() => { @@ -66,7 +68,13 @@ describe('ToastProvider', () => { // ๋‹ซ๊ธฐ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•œ ํ›„ ํ† ์ŠคํŠธ๊ฐ€ ์‚ฌ๋ผ์ง€๋Š”์ง€ ํ™•์ธ await waitFor(() => { - expect(screen.queryByText(TOAST_MESSAGE)).not.toBeInTheDocument(); + expect(screen.queryByText(TOAST_CONFIG.message)).not.toBeInTheDocument(); }); }); + + it('Provider์—†์ด useToast ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์—๋Ÿฌ๋ฅผ ๋˜์ง„๋‹ค.', () => { + expect(() => { + const _ = renderHook(() => useToast()); + }).toThrow('useToast๋Š” ToastProvider ๋‚ด์—์„œ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.'); + }); }); diff --git a/client/src/hooks/useToast/useToast.tsx b/client/src/hooks/useToast/useToast.tsx index e47d99c50..189847405 100644 --- a/client/src/hooks/useToast/useToast.tsx +++ b/client/src/hooks/useToast/useToast.tsx @@ -1,50 +1,13 @@ -/** @jsxImportSource @emotion/react */ -import {useEffect, useState} from 'react'; +import {useContext} from 'react'; -import {ToastMessage, ToastOptions, ToastArgs} from 'types/toastType'; - -import toastEventManager from './toastEventManager'; -import {TOAST_EVENT} from './toastEventManager.type'; - -const DEFAULT_TIME = 3000; - -type Toast = { - message: ToastMessage; - options: ToastOptions; -}; +import {ToastContext} from './ToastProvider'; export const useToast = () => { - const [currentToast, setCurrentToast] = useState(null); - - const showToast = (message: ToastMessage, options: ToastOptions) => { - setCurrentToast({message, options}); - }; - - const closeToast = () => { - setCurrentToast(null); - }; - - const setAutoCloseTimer = () => { - if (!currentToast) return; - - const showingTime = currentToast.options.showingTime || DEFAULT_TIME; - const timer = setTimeout(() => setCurrentToast(null), showingTime); - - return () => clearTimeout(timer); - }; - - useEffect(() => { - if (currentToast?.options.isAutoClosed) setAutoCloseTimer(); - - return; - }, [currentToast]); + const context = useContext(ToastContext); - useEffect(() => { - toastEventManager.addEventHandler({eventType: TOAST_EVENT.show, callback: showToast}); - }, []); + if (!context) { + throw new Error('useToast๋Š” ToastProvider ๋‚ด์—์„œ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.'); + } - return { - currentToast, - closeToast, - }; + return context; }; diff --git a/client/src/index.tsx b/client/src/index.tsx index cb3fcb955..17f98655f 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -5,6 +5,11 @@ import * as Sentry from '@sentry/react'; import router from './router'; +// async function enableMocking() { +// const {worker} = await import('./mocks/browser'); +// return worker.start(); +// } + Sentry.init({ dsn: 'https://81685591a3234c689be8c48959b04c88@o4507739935997952.ingest.us.sentry.io/4507739943272448', integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()], @@ -18,11 +23,6 @@ Sentry.init({ }); // MSW ๋ชจํ‚น์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์•„๋ž˜ ์ฃผ์„์„ ํ•ด์ œํ•˜๊ณ  saveํ•ด์ฃผ์„ธ์š”. -// async function enableMocking() { -// const {worker} = await import('./mocks/browser'); -// return worker.start(); -// } - // enableMocking().then(() => { ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/client/src/mocks/handlers.ts b/client/src/mocks/handlers.ts index d4347bc5b..4189b2d66 100644 --- a/client/src/mocks/handlers.ts +++ b/client/src/mocks/handlers.ts @@ -1,15 +1,15 @@ import {authHandler} from './handlers/authHandlers'; import {eventHandler} from './handlers/eventHandlers'; import {reportHandlers} from './handlers/reportHandlers'; +import {stepListHandler} from './handlers/stepListHandler'; import {testHandler} from './handlers/testHandlers'; -import {billHandler} from './handlers/billHandler'; -import {memberHandler} from './handlers/memberHandler'; +import {memberReportInActionHandler} from './handlers/memberReportInActionHandlers'; export const handlers = [ ...authHandler, ...eventHandler, - ...billHandler, - ...memberHandler, ...testHandler, + ...stepListHandler, ...reportHandlers, + ...memberReportInActionHandler, ]; diff --git a/client/src/mocks/handlers/authHandlers.ts b/client/src/mocks/handlers/authHandlers.ts index 00000b1e8..31532eea7 100644 --- a/client/src/mocks/handlers/authHandlers.ts +++ b/client/src/mocks/handlers/authHandlers.ts @@ -1,56 +1,100 @@ -import {http, HttpResponse} from 'msw'; +import {HttpResponse, http} from 'msw'; -import {ADMIN_API_PREFIX, USER_API_PREFIX} from '@apis/endpointPrefix'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; import {PASSWORD_LENGTH} from '@constants/password'; -import {MOCK_API_PREFIX} from '@mocks/mockEndpointPrefix'; +import { + EXPIRED_TOKEN_FOR_TEST, + FORBIDDEN_TOKEN_FOR_TEST, + VALID_PASSWORD_FOR_TEST, + VALID_TOKEN_FOR_TEST, +} from '@mocks/validValueForTest'; + +type PostLoginParams = { + eventId: string; +}; + +type PostLoginRequestBody = { + password: string; +}; export const authHandler = [ - // POST /api/eventId/auth (requestPostAuthentication) - http.post(`${MOCK_API_PREFIX}${ADMIN_API_PREFIX}/:eventId/auth`, () => { - return new HttpResponse(null, {status: 200}); + http.post(`${TEMP_PREFIX}/:eventId/auth`, ({cookies}) => { + const token = cookies['eventToken']; + + if (token === VALID_TOKEN_FOR_TEST) { + return new HttpResponse(null, { + status: 200, + }); + } else if (token === EXPIRED_TOKEN_FOR_TEST) { + return HttpResponse.json( + { + errorCode: 'TOKEN_EXPIRED', + message: '๋งŒ๋ฃŒ๋œ ํ† ํฐ์ž…๋‹ˆ๋‹ค.', + }, + {status: 401}, + ); + } else if (token === FORBIDDEN_TOKEN_FOR_TEST) { + return HttpResponse.json( + { + errorCode: 'FORBIDDEN', + message: '์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค.', + }, + {status: 401}, + ); + } else if (token === undefined) { + return HttpResponse.json( + { + errorCode: 'TOKEN_NOT_FOUND', + message: 'ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.', + }, + {status: 401}, + ); + } else { + return HttpResponse.json( + { + errorCode: 'TOKEN_INVALID', + message: '์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค.', + }, + {status: 401}, + ); + } }), - // POST /api/eventId/login (requestPostToken) - http.post<{eventId: string}, {password: string}>( - `${MOCK_API_PREFIX}${USER_API_PREFIX}/:eventId/login`, - async ({params, request}) => { - const {eventId} = params; + // TODO: (@weadie) any๋ฅผ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š”.. any๊ฐ€ ์žˆ๋Š” ์œ„์น˜๊ฐ€ ์ด handlerํ•จ์ˆ˜์˜ responseBodyํƒ€์ž…์ธ๋ฐ, ์•„๋ž˜์ฒ˜๋Ÿผ returnํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์˜ˆ์‹œ๊ฐ€ ๊ณต๋ฌธ์— ์—†์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ๊นŒ๋ฉด ๋˜๊ฒ ์ง€๋งŒ ์‹œ๊ฐ„์ด ์•„๊น๊ณ  ์•Œ์•„๋‚ธ๋‹ค๊ณ  ํ•ด์„œ ์ด responseBody ํƒ€์ž…์€ ์‚ฌ์‹ค ์ค‘์š”ํ•œ๊ฒŒ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— any๋กœ ๋Œ€์ฒดํ•˜์˜€์Šต๋‹ˆ๋‹ค. + http.post( + `${TEMP_PREFIX}/:eventId/login`, + async ({request}) => { const {password} = await request.json(); - if (!password) { + if (password === String(VALID_PASSWORD_FOR_TEST)) { + return new HttpResponse(null, { + headers: { + 'Set-Cookie': 'eventToken=abc-123', + }, + }); + } else if (password.length < PASSWORD_LENGTH) { return HttpResponse.json( { - errorCode: 'REQUEST_EMPTY', - message: '๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.', + errorCode: 'EVENT_PASSWORD_FORMAT_INVALID', + message: `๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ${PASSWORD_LENGTH}์ž๋ฆฌ ์ˆซ์ž๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.`, }, - {status: 400}, + {status: 401}, ); - } - if (password.length !== PASSWORD_LENGTH) { + } else if (password === undefined) { return HttpResponse.json( { - errorCode: 'PASSWORD_INVALID', - message: `๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ${PASSWORD_LENGTH}์ž๋ฆฌ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.`, + errorCode: 'REQUEST_EMPTY', + message: '๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.', }, - {status: 400}, + {status: 401}, ); - } - - // ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ 1234์ธ ๊ฒฝ์šฐ๋งŒ ์„ฑ๊ณต์œผ๋กœ ์ฒ˜๋ฆฌ - if (password === '1234') { - return new HttpResponse(null, { - status: 200, - headers: { - 'Set-Cookie': `eventToken=${eventId}-token`, - }, - }); } else { return HttpResponse.json( { - errorCode: 'PASSWORD_INCORRECT', - message: '๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.', + errorCode: 'PASSWORD_INVALID', + message: '๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.', }, {status: 401}, ); diff --git a/client/src/mocks/handlers/billHandler.ts b/client/src/mocks/handlers/billHandler.ts deleted file mode 100644 index 597ff3a1e..000000000 --- a/client/src/mocks/handlers/billHandler.ts +++ /dev/null @@ -1,115 +0,0 @@ -import {http, HttpResponse, PathParams} from 'msw'; - -import {ADMIN_API_PREFIX, USER_API_PREFIX} from '@apis/endpointPrefix'; - -import {billData, billDetailsData} from '@mocks/sharedState'; - -import {MOCK_API_PREFIX} from './../mockEndpointPrefix'; - -interface BillDetailsData { - [key: string]: {billDetails: {id: number; memberName: string; price: string}[]}; -} - -export const billHandler = [ - // GET /api/eventId/bills - http.get(`${MOCK_API_PREFIX}${USER_API_PREFIX}/:eventId/bills`, () => { - return HttpResponse.json(billData); - }), - - // GET /api/eventId/bills/billId/fixed - http.get(`${MOCK_API_PREFIX}${USER_API_PREFIX}/:eventId/bills/:billId/fixed`, ({params}) => { - const {billId} = params; - const billDetails = (billDetailsData as unknown as BillDetailsData)[billId as keyof BillDetailsData]; - return HttpResponse.json(billDetails); - }), - - // POST /api/eventId/bills - http.post( - `${MOCK_API_PREFIX}${ADMIN_API_PREFIX}/:eventId/bills`, - async ({request}) => { - try { - const {title, price, members} = await request.json(); - const newBill = {id: Date.now(), title, price, isFixed: false}; - - const lastStep = billData.steps[billData.steps.length - 1]; - const isSameMembers = JSON.stringify(lastStep.members.map(m => m.id).sort()) === JSON.stringify(members.sort()); - - if (isSameMembers) { - lastStep.bills.push(newBill); - } else { - billData.steps.push({ - bills: [newBill], - members: members.map(id => ({id, name: `Member ${id}`})), - }); - } - - (billDetailsData as unknown as BillDetailsData)[newBill.id.toString()] = { - billDetails: members.map((id, index) => ({ - id, - memberName: - billData.steps.flatMap(step => step.members).find(member => member.id === id)?.name || `Member ${id}`, - price: (Math.floor(price / members.length) + (index < price % members.length ? 1 : 0)).toString(), - })), - }; - - return HttpResponse.json({status: 200}); - } catch (error) { - return HttpResponse.json({message: 'Internal Server Error'}, {status: 500}); - } - }, - ), - - // DELETE /api/eventId/bills/billId - http.delete(`${MOCK_API_PREFIX}${ADMIN_API_PREFIX}/:eventId/bills/:billId`, ({params}) => { - const {billId} = params; - billData.steps.forEach(step => { - step.bills = step.bills.filter(bill => bill.id !== Number(billId)); - }); - delete (billDetailsData as unknown as BillDetailsData)[billId as keyof BillDetailsData]; - return HttpResponse.json({status: 200}); - }), - - // PUT /api/eventId/bills/billId - http.put( - `${MOCK_API_PREFIX}${ADMIN_API_PREFIX}/:eventId/bills/:billId`, - async ({params, request}) => { - const {billId} = params; - const {title, price} = await request.json(); - - billData.steps.forEach(step => { - const billIndex = step.bills.findIndex(bill => bill.id === Number(billId)); - if (billIndex !== -1) { - step.bills[billIndex] = {...step.bills[billIndex], title, price}; - } - }); - - return HttpResponse.json({status: 200}); - }, - ), - - // PUT /api/eventId/bills/billId/fixed - http.put( - `${MOCK_API_PREFIX}${ADMIN_API_PREFIX}/:eventId/bills/:billId/fixed`, - async ({params, request}) => { - const {billId} = params; - const {billDetails} = await request.json(); - - (billDetailsData as unknown as BillDetailsData)[billId as keyof BillDetailsData] = { - billDetails: billDetails.map(detail => ({ - id: detail.id, - memberName: 'Unknown', - price: detail.price.toString(), - })), - }; - - billData.steps.forEach(step => { - const billIndex = step.bills.findIndex(bill => bill.id === Number(billId)); - if (billIndex !== -1) { - step.bills[billIndex].isFixed = true; - } - }); - - return HttpResponse.json({status: 200}); - }, - ), -]; diff --git a/client/src/mocks/handlers/eventHandlers.ts b/client/src/mocks/handlers/eventHandlers.ts index 1b06c5f9d..351993e16 100644 --- a/client/src/mocks/handlers/eventHandlers.ts +++ b/client/src/mocks/handlers/eventHandlers.ts @@ -1,64 +1,55 @@ -import type {EventId} from 'types/serviceType'; +import {HttpResponse, http} from 'msw'; -import {http, HttpResponse} from 'msw'; +import {RequestPostNewEvent, ResponsePostNewEvent} from '@apis/request/event'; -import {ADMIN_API_PREFIX, USER_API_PREFIX} from '@apis/endpointPrefix'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; -import {VALID_EVENT_NAME_LENGTH_IN_SERVER} from '@mocks/serverConstants'; -import {MOCK_API_PREFIX} from '@mocks/mockEndpointPrefix'; -import {eventData} from '@mocks/sharedState'; - -export const eventHandler = [ - // POST /api/events (requestPostEvent) - http.post(`${MOCK_API_PREFIX}${USER_API_PREFIX}`, async ({request}) => { - const {eventName, password} = await request.json(); - - if ( - eventName.length < VALID_EVENT_NAME_LENGTH_IN_SERVER.min || - eventName.length > VALID_EVENT_NAME_LENGTH_IN_SERVER.max - ) { - return HttpResponse.json( - { - errorCode: 'EVENT_NAME_LENGTH_INVALID', - message: 'ํ–‰์‚ฌ ์ด๋ฆ„์€ 2์ž ์ด์ƒ 30์ž ์ดํ•˜๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.', - }, - {status: 400}, - ); - } - - if (password.length !== 4) { - return HttpResponse.json( - { - errorCode: 'EVENT_PASSWORD_FORMAT_INVALID', - message: '๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” 4์ž๋ฆฌ ์ˆซ์ž๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.', - }, - {status: 400}, - ); - } +import {PASSWORD_LENGTH} from '@constants/password'; - const eventId: EventId = {eventId: 'mock-event-id'}; - return HttpResponse.json(eventId, { - status: 201, - headers: { - 'Set-Cookie': 'eventToken=mock-event-token', - }, - }); - }), +import {VALID_EVENT_NAME_LENGTH_IN_SERVER} from '@mocks/serverConstants'; - // GET /api/events/:eventId (requestGetEvent) - http.get(`${MOCK_API_PREFIX}${USER_API_PREFIX}/:eventId`, () => { - return HttpResponse.json(eventData); - }), +type ErrorResponseBody = { + errorCode: string; + message: string; +}; - // PATCH /api/admin/events/:eventId (requestPatchEvent) - http.patch( - `${MOCK_API_PREFIX}${ADMIN_API_PREFIX}/:eventId`, +export const eventHandler = [ + http.post( + `${TEMP_PREFIX}`, async ({request}) => { - const updates = await request.json(); - - Object.assign(eventData, updates); - - return HttpResponse.json({status: 200}); + const {eventName, password} = await request.json(); + + if (String(password).length < PASSWORD_LENGTH) { + return HttpResponse.json( + { + errorCode: 'EVENT_PASSWORD_FORMAT_INVALID', + message: '๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” 4์ž๋ฆฌ ์ˆซ์ž๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.', + }, + {status: 401}, + ); + } else if ( + eventName.length < VALID_EVENT_NAME_LENGTH_IN_SERVER.min || + eventName.length > VALID_EVENT_NAME_LENGTH_IN_SERVER.max + ) { + return HttpResponse.json( + { + errorCode: 'EVENT_NAME_LENGTH_INVALID', + message: `ํ–‰์‚ฌ ์ด๋ฆ„์€ 2์ž ์ด์ƒ 30์ž ์ดํ•˜๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ์ด๋ฆ„ ๊ธธ์ด : ${eventName.length}`, + }, + {status: 401}, + ); + } else { + return HttpResponse.json( + { + eventId: 'eventId', + }, + { + headers: { + 'Set-Cookie': 'eventToken=abc-123', + }, + }, + ); + } }, ), ]; diff --git a/client/src/mocks/handlers/memberHandler.ts b/client/src/mocks/handlers/memberHandler.ts deleted file mode 100644 index 97233c8b5..000000000 --- a/client/src/mocks/handlers/memberHandler.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {http, HttpResponse, PathParams} from 'msw'; - -import {AllMembers, Members} from 'types/serviceType'; - -import {ADMIN_API_PREFIX, USER_API_PREFIX} from '@apis/endpointPrefix'; - -import {MOCK_API_PREFIX} from '@mocks/mockEndpointPrefix'; -import {memberData} from '@mocks/sharedState'; - -export const memberHandler = [ - // POST /api/eventId/members (requestPostMember) - http.post( - `${MOCK_API_PREFIX}${ADMIN_API_PREFIX}/:eventId/members`, - async ({request}) => { - const {members: newMembers} = await request.json(); - const addedMembers = newMembers.map((member, index) => ({ - id: memberData.members.length + index + 1, - name: member.name, - isDeposited: false, - })); - - memberData.members = [...memberData.members, ...addedMembers]; - - return HttpResponse.json({members: addedMembers}, {status: 201}); - }, - ), - - // DELETE /api/eventId/members/memberId (requestDeleteMember) - http.delete(`${MOCK_API_PREFIX}${ADMIN_API_PREFIX}/:eventId/members/:memberId`, ({params}) => { - const {memberId} = params; - memberData.members = memberData.members.filter(member => member.id !== Number(memberId)); - return HttpResponse.json({status: 200}); - }), - - // PUT /api/eventId/members (requestPutMember) - http.put( - `${MOCK_API_PREFIX}${ADMIN_API_PREFIX}/:eventId/members`, - async ({request}) => { - const {members: updatedMembers} = await request.json(); - - memberData.members = memberData.members.map(member => { - const updatedMember = updatedMembers.find(m => m.id === member.id); - return updatedMember ? {...member, ...updatedMember} : member; - }); - - return HttpResponse.json({status: 200}); - }, - ), - - // GET /api/eventId/members/current (requestGetCurrentMember) - http.get(`${MOCK_API_PREFIX}${USER_API_PREFIX}/:eventId/members/current`, () => { - const currentMembers: Members = { - members: memberData.members.map(({id, name}) => ({id, name})), - }; - return HttpResponse.json(currentMembers); - }), - - // GET /api/eventId/members (requestGetAllMember) - http.get(`${MOCK_API_PREFIX}${USER_API_PREFIX}/:eventId/members`, () => { - return HttpResponse.json(memberData); - }), -]; diff --git a/client/src/mocks/handlers/memberReportInActionHandlers.ts b/client/src/mocks/handlers/memberReportInActionHandlers.ts new file mode 100644 index 000000000..45de357f1 --- /dev/null +++ b/client/src/mocks/handlers/memberReportInActionHandlers.ts @@ -0,0 +1,49 @@ +import {http, HttpResponse} from 'msw'; + +import {MemberReport} from 'types/serviceType'; + +import {TEMP_PREFIX} from '@apis/tempPrefix'; + +import memberReportInActionJson from '../memberReportListInAction.json'; + +let memberReportInActionMockData = memberReportInActionJson as MemberReport[]; + +type MemberReportListRequestParams = { + eventId: string; + actionId: string; +}; +type MemberReportListBody = {members: MemberReport[]}; + +export const memberReportInActionHandler = [ + http.get< + MemberReportListRequestParams, + MemberReportListBody, + any, + `${typeof TEMP_PREFIX}/:eventId/bill-actions/:actionId/fixed` + >(`${TEMP_PREFIX}/:eventId/bill-actions/:actionId/fixed`, ({params}) => { + const {actionId} = params; + + if (Number(actionId) === 123) { + return HttpResponse.json({ + members: memberReportInActionMockData, + }); + } + + return HttpResponse.json({ + members: memberReportInActionMockData.slice(0, 2), + }); + }), + + http.put( + `${TEMP_PREFIX}/:eventId/bill-actions/:actionId/fixed`, + async ({request}) => { + const {members} = await request.json(); + + memberReportInActionMockData = members; + + return HttpResponse.json({ + status: 200, + }); + }, + ), +]; diff --git a/client/src/mocks/handlers/reportHandlers.ts b/client/src/mocks/handlers/reportHandlers.ts index 5248fe82a..6b256d7d3 100644 --- a/client/src/mocks/handlers/reportHandlers.ts +++ b/client/src/mocks/handlers/reportHandlers.ts @@ -1,13 +1,13 @@ -import {http, HttpResponse} from 'msw'; +import {HttpResponse, http} from 'msw'; -import {USER_API_PREFIX} from '@apis/endpointPrefix'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; -import {MOCK_API_PREFIX} from '@mocks/mockEndpointPrefix'; -import {reportData} from '@mocks/sharedState'; +import reportListJson from '../reportList.json'; export const reportHandlers = [ - // GET /api/eventId/reports (requestGetMemberReport) - http.get(`${MOCK_API_PREFIX}${USER_API_PREFIX}/:eventId/reports`, () => { - return HttpResponse.json(reportData); + http.get(`${TEMP_PREFIX}/:eventId/actions/reports`, () => { + return HttpResponse.json({ + reports: reportListJson, + }); }), ]; diff --git a/client/src/mocks/handlers/stepListHandler.ts b/client/src/mocks/handlers/stepListHandler.ts new file mode 100644 index 000000000..d79b7b0b4 --- /dev/null +++ b/client/src/mocks/handlers/stepListHandler.ts @@ -0,0 +1,113 @@ +import {HttpResponse, http} from 'msw'; + +import {Bill, MemberType, StepList} from 'types/serviceType'; + +import {TEMP_PREFIX} from '@apis/tempPrefix'; + +import stepListJson from '../stepList.json'; + +type StepListResponseBody = { + step: StepList; +}; + +type PostMemberListRequestBody = { + members: string[]; + status: MemberType; +}; + +type PostBillListRequestBody = { + actions: Bill[]; +}; + +let stepListMockData = stepListJson; + +export const stepListHandler = [ + http.get( + `${TEMP_PREFIX}/:eventId/actions`, + () => { + return HttpResponse.json({ + steps: stepListMockData, + }); + }, + ), + + http.get(`${TEMP_PREFIX}/:eventId/members`, () => { + return HttpResponse.json({ + memberNames: stepListMockData + .filter(({type}) => type !== 'BILL') + .map(({actions}) => actions.map(({name}) => name)) + .flat(), + }); + }), + + http.delete<{actionId: string}>(`${TEMP_PREFIX}/:eventId/member-actions/:actionId`, ({params}) => { + const {actionId} = params; + + if (parseInt(actionId) === 999) { + return HttpResponse.json( + { + errorCode: 'MEMBER_ACTION_STATUS_INVALID', + message: 'actionId๋Š” 999์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.(๊ณ ์˜๋กœ ๋งŒ๋“  ์—๋Ÿฌ์ž„)', + }, + {status: 401}, + ); + } else { + return HttpResponse.json({ + status: 200, + }); + } + }), + + http.post( + `${TEMP_PREFIX}/:eventId/member-actions`, + async ({request}) => { + const {members, status} = await request.json(); + stepListMockData = [ + ...stepListJson, + { + type: status, + stepName: '์˜์ฐจ์˜์ฐจ', + members: status === 'IN' ? members : [], + actions: members.map(name => ({ + actionId: 999, + name, + price: 0, + sequence: 999, + isFixed: false, + })), + }, + ]; + + return HttpResponse.json({ + status: 200, + }); + }, + ), + + http.post( + `${TEMP_PREFIX}/:eventId/bill-actions`, + async ({request}) => { + const {actions} = await request.json(); + + stepListMockData = [ + ...stepListJson, + { + type: 'BILL', + stepName: '๋ฐฅ์Šค์นด์ด', + members: [], + actions: actions.map(({title, price}) => ({ + actionId: 999, + name: title, + price, + sequence: 999, + isFixed: false, + })), + }, + ]; + + return HttpResponse.json({ + status: 200, + }); + }, + ), +]; diff --git a/client/src/mocks/imageFileMock.ts b/client/src/mocks/imageFileMock.ts deleted file mode 100644 index b59aedd2d..000000000 --- a/client/src/mocks/imageFileMock.ts +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - process() { - return { - code: 'module.exports = "imageFileMock";', - }; - }, -}; diff --git a/client/src/mocks/invalidMemberStepList.json b/client/src/mocks/invalidMemberStepList.json new file mode 100644 index 000000000..33ca77e4c --- /dev/null +++ b/client/src/mocks/invalidMemberStepList.json @@ -0,0 +1,100 @@ +[ + { + "type": "IN", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 999, + "name": "๋ง์ตธ", + "price": null, + "sequence": 1, + "isFixed": false + }, + { + "actionId": 2, + "name": "๋ฐฑํ˜ธ", + "price": null, + "sequence": 2, + "isFixed": false + } + ] + }, + { + "type": "BILL", + "stepName": "1์ฐจ", + "members": ["๋ง์ตธ", "๋ฐฑํ˜ธ"], + "actions": [ + { + "actionId": 3, + "name": "๊ฐ์žํƒ•", + "price": 10000, + "sequence": 3, + "isFixed": false + }, + { + "actionId": 4, + "name": "์ธ์ƒ๋„ค์ปท", + "price": 10000, + "sequence": 4, + "isFixed": false + } + ] + }, + { + "type": "IN", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 5, + "name": "์†Œํ•˜", + "price": null, + "sequence": 5, + "isFixed": false + }, + { + "actionId": 6, + "name": "์›จ๋””", + "price": null, + "sequence": 6, + "isFixed": false + } + ] + }, + { + "type": "BILL", + "stepName": "2์ฐจ", + "members": ["์†Œํ•˜", "์›จ๋””"], + "actions": [ + { + "actionId": 9, + "name": "๋…ธ๋ž˜๋ฐฉ", + "price": 20000, + "sequence": 10, + "isFixed": false + } + ] + }, + { + "type": "OUT", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 7, + "name": "๋ง์ตธ", + "price": null, + "sequence": 7, + "isFixed": false + }, + { + "actionId": 8, + "name": "๋ฐฑํ˜ธ", + "price": null, + "sequence": 8, + "isFixed": false + } + ] + } +] diff --git a/client/src/mocks/memberActionStepList.json b/client/src/mocks/memberActionStepList.json new file mode 100644 index 000000000..734db4a75 --- /dev/null +++ b/client/src/mocks/memberActionStepList.json @@ -0,0 +1,23 @@ +[ + { + "type": "IN", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 1, + "name": "๋ง์ตธ", + "price": null, + "sequence": 1, + "isFixed": false + }, + { + "actionId": 2, + "name": "๋ฐฑํ˜ธ", + "price": null, + "sequence": 2, + "isFixed": false + } + ] + } +] diff --git a/client/src/mocks/memberReportListInAction.json b/client/src/mocks/memberReportListInAction.json new file mode 100644 index 000000000..2e24670cb --- /dev/null +++ b/client/src/mocks/memberReportListInAction.json @@ -0,0 +1,6 @@ +[ + {"name": "๋ง์ตธ", "price": 25000, "isFixed": false}, + {"name": "์ด์ƒ", "price": 25000, "isFixed": false}, + {"name": "์†Œํ•˜", "price": 25000, "isFixed": false}, + {"name": "์ฟ ํ‚ค", "price": 25000, "isFixed": false} +] diff --git a/client/src/mocks/memberReportSearchList.json b/client/src/mocks/memberReportSearchList.json new file mode 100644 index 000000000..dfcb684b1 --- /dev/null +++ b/client/src/mocks/memberReportSearchList.json @@ -0,0 +1,10 @@ +[ + {"name": "๋ง์ตธ", "price": 1033200}, + {"name": "์ด์ƒ", "price": 10100}, + {"name": "์†Œํ•˜", "price": 10000}, + {"name": "์ฟ ํ‚ค", "price": 100012}, + {"name": "ํ† ๋‹ค๋ฆฌ", "price": 1001230}, + {"name": "๊ฐ์ž", "price": 1012300}, + {"name": "๋ฐฑํ˜ธ", "price": 10300}, + {"name": "์›จ๋””", "price": 1000} +] diff --git a/client/src/mocks/mockEndpointPrefix.ts b/client/src/mocks/mockEndpointPrefix.ts deleted file mode 100644 index d02762e51..000000000 --- a/client/src/mocks/mockEndpointPrefix.ts +++ /dev/null @@ -1,3 +0,0 @@ -import {BASE_URL} from '@apis/baseUrl'; - -export const MOCK_API_PREFIX = typeof window !== 'undefined' ? `${BASE_URL.HD}` : ''; diff --git a/client/src/mocks/reportList.json b/client/src/mocks/reportList.json new file mode 100644 index 000000000..a663eb9fd --- /dev/null +++ b/client/src/mocks/reportList.json @@ -0,0 +1,18 @@ +[ + { + "name": "์†Œํ•˜", + "price": 40000 + }, + { + "name": "๊ฐ์ž", + "price": 20000 + }, + { + "name": "์ฟ ํ‚ค", + "price": 40000 + }, + { + "name": "ํ† ๋‹ค๋ฆฌ", + "price": 0 + } +] diff --git a/client/src/mocks/sharedState.ts b/client/src/mocks/sharedState.ts deleted file mode 100644 index 5f584092d..000000000 --- a/client/src/mocks/sharedState.ts +++ /dev/null @@ -1,143 +0,0 @@ -export let eventData = { - eventName: 'ํ–‰๋™๋Œ€์žฅ ์•ผ์œ ํšŒ', - bankName: '', - accountNumber: '000000-01-121212', -}; - -export let memberData = { - members: [ - {id: 1, name: '๋ง์ตธ', isDeposited: false}, - {id: 2, name: '๋ฐฑํ˜ธ', isDeposited: true}, - {id: 3, name: '๊ฐ์ž', isDeposited: true}, - {id: 4, name: '์ด์ƒ', isDeposited: false}, - {id: 5, name: '์†Œํ•˜', isDeposited: false}, - {id: 6, name: '์›จ๋””', isDeposited: false}, - {id: 7, name: '์ฟ ํ‚ค', isDeposited: false}, - ], -}; - -export let billData = { - steps: [ - { - bills: [ - {id: 1, title: '์ปคํ”ผ', price: 10000, isFixed: false}, - {id: 2, title: '์ธ์ƒ๋„ค์ปท', price: 20000, isFixed: false}, - ], - members: [ - {id: 1, name: '๋ง์ตธ'}, - {id: 2, name: '๋ฐฑํ˜ธ'}, - ], - }, - { - bills: [{id: 3, title: '๋งฅ์ฃผ', price: 20000, isFixed: true}], - members: [ - {id: 1, name: '๋ง์ตธ'}, - {id: 2, name: '๋ฐฑํ˜ธ'}, - {id: 3, name: '๊ฐ์ž'}, - ], - }, - { - bills: [{id: 4, title: '๋ฝ•์Ÿ์ด์กฑ', price: 70000, isFixed: false}], - members: [ - {id: 1, name: '๋ง์ตธ'}, - {id: 2, name: '๋ฐฑํ˜ธ'}, - {id: 3, name: '๊ฐ์ž'}, - {id: 4, name: '์ด์ƒ'}, - {id: 5, name: '์†Œํ•˜'}, - {id: 6, name: '์›จ๋””'}, - {id: 7, name: '์ฟ ํ‚ค'}, - ], - }, - ], -}; - -export let billDetailsData = { - '1': { - billDetails: [ - { - id: 1, - memberName: '๋ง์ตธ', - price: 5000, - isFixed: false, - }, - { - id: 2, - memberName: '๋ฐฑํ˜ธ', - price: 5000, - isFixed: false, - }, - ], - }, - '2': { - billDetails: [ - { - id: 1, - memberName: '๋ง์ตธ', - price: 10000, - isFixed: false, - }, - { - id: 2, - memberName: '๋ฐฑํ˜ธ', - price: 10000, - isFixed: false, - }, - ], - }, - '3': { - billDetails: [ - { - id: 1, - memberName: '๋ง์ตธ', - price: 5000, - isFixed: false, - }, - { - id: 2, - memberName: '๋ฐฑํ˜ธ', - price: 10000, - isFixed: true, - }, - { - id: 2, - memberName: '๊ฐ์ž', - price: 5000, - isFixed: false, - }, - ], - }, - '4': { - billDetails: [ - {id: 1, memberName: '๋ง์ตธ', price: 10000, isFixed: false}, - {id: 2, memberName: '๋ฐฑํ˜ธ', price: 10000, isFixed: false}, - {id: 3, memberName: '๊ฐ์ž', price: 10000, isFixed: false}, - {id: 4, memberName: '์ด์ƒ', price: 10000, isFixed: false}, - {id: 5, memberName: '์†Œํ•˜', price: 10000, isFixed: false}, - {id: 6, memberName: '์›จ๋””', price: 10000, isFixed: false}, - {id: 7, memberName: '์ฟ ํ‚ค', price: 10000, isFixed: false}, - ], - }, -}; - -export let reportData = { - reports: [ - { - memberId: 1, - memberName: '๋ง์ตธ', - price: 20000, - isDeposited: false, - }, - { - memberId: 2, - memberName: '๋ฐฑํ˜ธ', - price: 25000, - isDeposited: true, - }, - { - memberId: 3, - memberName: '๊ฐ์ž', - price: 5000, - isDeposited: true, - }, - ], -}; diff --git a/client/src/mocks/stepList.json b/client/src/mocks/stepList.json new file mode 100644 index 000000000..355692d58 --- /dev/null +++ b/client/src/mocks/stepList.json @@ -0,0 +1,100 @@ +[ + { + "type": "IN", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 1, + "name": "๋ง์ตธ", + "price": null, + "sequence": 1, + "isFixed": false + }, + { + "actionId": 2, + "name": "๋ฐฑํ˜ธ", + "price": null, + "sequence": 2, + "isFixed": false + } + ] + }, + { + "type": "BILL", + "stepName": "1์ฐจ", + "members": ["๋ง์ตธ", "๋ฐฑํ˜ธ"], + "actions": [ + { + "actionId": 3, + "name": "๊ฐ์žํƒ•", + "price": 10000, + "sequence": 3, + "isFixed": false + }, + { + "actionId": 4, + "name": "์ธ์ƒ๋„ค์ปท", + "price": 10000, + "sequence": 4, + "isFixed": false + } + ] + }, + { + "type": "IN", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 5, + "name": "์†Œํ•˜", + "price": null, + "sequence": 5, + "isFixed": false + }, + { + "actionId": 6, + "name": "์›จ๋””", + "price": null, + "sequence": 6, + "isFixed": false + } + ] + }, + { + "type": "BILL", + "stepName": "2์ฐจ", + "members": ["์†Œํ•˜", "์›จ๋””"], + "actions": [ + { + "actionId": 9, + "name": "๋…ธ๋ž˜๋ฐฉ", + "price": 20000, + "sequence": 10, + "isFixed": false + } + ] + }, + { + "type": "OUT", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 7, + "name": "๋ง์ตธ", + "price": null, + "sequence": 7, + "isFixed": false + }, + { + "actionId": 8, + "name": "๋ฐฑํ˜ธ", + "price": null, + "sequence": 8, + "isFixed": false + } + ] + } +] diff --git a/client/src/pages/AccountPage/Account.tsx b/client/src/pages/AccountPage/Account.tsx deleted file mode 100644 index 0490ead31..000000000 --- a/client/src/pages/AccountPage/Account.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import {useState} from 'react'; -import {useLocation, useNavigate} from 'react-router-dom'; - -import BankSelectModal from '@components/Modal/BankSelectModal/BankSelectModal'; - -import useAccount from '@hooks/useAccount'; - -import {FixedButton, Flex, FunnelLayout, LabelInput, MainLayout, Top, TopNav} from '@components/Design'; - -import getDeletedLastPath from '@utils/getDeletedLastPath'; - -const Account = () => { - const navigate = useNavigate(); - const location = useLocation(); - - const [isBottomSheetOpen, setIsBottomSheetOpen] = useState(false); - - const { - bankName, - accountNumber, - accountNumberErrorMessage, - canSubmit, - selectBank, - handleAccount, - handleAccountOnPaste, - enrollAccount, - } = useAccount(); - - const enrollAccountAndNavigateAdmin = async () => { - await enrollAccount(); - navigate(getDeletedLastPath(location.pathname)); - }; - - return ( - - - - - - - - - - - setIsBottomSheetOpen(true)} - /> - - {isBottomSheetOpen && ( - - )} - - - navigate(-1)}> - ํ™•์ธ - - - ); -}; - -export default Account; diff --git a/client/src/pages/AddBillFunnel/AddBillFunnel.tsx b/client/src/pages/AddBillFunnel/AddBillFunnel.tsx deleted file mode 100644 index acb13d698..000000000 --- a/client/src/pages/AddBillFunnel/AddBillFunnel.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import {Member} from 'types/serviceType'; - -import useAddBillFunnel from '@hooks/useAddBillFunnel'; - -import {MainLayout, TopNav} from '@components/Design'; - -import PriceStep from './steps/PriceStep'; -import {TitleStep} from './steps/TitleStep'; -import MembersStep from './steps/MembersStep'; - -export interface BillInfo { - price: string; - title: string; - members: Member[]; -} - -const AddBillFunnel = () => { - const {step, setStep, billInfo, setBillInfo, currentMembers} = useAddBillFunnel(); - - return ( - - - - - {step === 'price' && } - {step === 'title' && } - {step === 'members' && ( - - )} - - ); -}; - -export default AddBillFunnel; diff --git a/client/src/pages/AddBillFunnel/steps/MembersStep.tsx b/client/src/pages/AddBillFunnel/steps/MembersStep.tsx deleted file mode 100644 index fe4052d8e..000000000 --- a/client/src/pages/AddBillFunnel/steps/MembersStep.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import {css} from '@emotion/react'; - -import Top from '@components/Design/components/Top/Top'; -import ChipButton from '@components/Design/components/ChipButton/ChipButton'; -import {Member} from 'types/serviceType'; - -import useMembersStep from '@hooks/useMembersStep'; -import {BillStep} from '@hooks/useAddBillFunnel'; - -import {FixedButton, Flex, LabelInput, Text} from '@components/Design'; - -import {BillInfo} from '../AddBillFunnel'; - -interface Props { - billInfo: BillInfo; - setBillInfo: React.Dispatch>; - setStep: React.Dispatch>; - currentMembers: Member[]; -} - -const MembersStep = ({billInfo, setBillInfo, currentMembers, setStep}: Props) => { - const { - errorMessage, - nameInput, - inputRef, - handleNameInputChange, - handleNameInputEnter, - isPendingPostBill, - isPendingPostMembers, - canSubmitMembers, - handlePostBill, - handlePrevStep, - } = useMembersStep({billInfo, setBillInfo, currentMembers, setStep}); - - return ( - <> -

    - - - - - -
    - - - ์ฐธ์—ฌ ์ธ์› - - {`์ด ${billInfo.members.length}๋ช…`} - -
    - {billInfo.members.map(member => ( - setBillInfo(prev => ({...prev, members: prev.members.filter(name => name !== member)}))} - /> - ))} -
    -
    -
    - - ์ถ”๊ฐ€์™„๋ฃŒ - - - ); -}; - -export default MembersStep; diff --git a/client/src/pages/AddBillFunnel/steps/PriceStep.tsx b/client/src/pages/AddBillFunnel/steps/PriceStep.tsx deleted file mode 100644 index fea267860..000000000 --- a/client/src/pages/AddBillFunnel/steps/PriceStep.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import {css} from '@emotion/react'; -import {useNavigate} from 'react-router-dom'; - -import AmountInput from '@components/AmountInput/AmountInput'; -import NumberKeyboard from '@components/Design/components/NumberKeyboard/NumberKeyboard'; -import Top from '@components/Design/components/Top/Top'; - -import usePriceStep from '@hooks/usePriceStep'; -import {BillStep} from '@hooks/useAddBillFunnel'; - -import {FixedButton} from '@components/Design'; - -import RULE from '@constants/rule'; - -import {BillInfo} from '../AddBillFunnel'; - -interface Props { - billInfo: BillInfo; - setBillInfo: React.Dispatch>; - setStep: React.Dispatch>; -} - -const PriceStep = ({billInfo, setBillInfo, setStep}: Props) => { - const navigate = useNavigate(); - const {handleNumberKeyboardChange, handleNextStep} = usePriceStep({setBillInfo, setStep}); - - return ( - <> -
    - - - - -
    -
    - -
    - navigate(-1)}> - ๋‹ค์Œ์œผ๋กœ - - - ); -}; - -export default PriceStep; diff --git a/client/src/pages/AddBillFunnel/steps/TitleStep.tsx b/client/src/pages/AddBillFunnel/steps/TitleStep.tsx deleted file mode 100644 index eb910991f..000000000 --- a/client/src/pages/AddBillFunnel/steps/TitleStep.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import {css} from '@emotion/react'; - -import Top from '@components/Design/components/Top/Top'; - -import useTitleStep from '@hooks/useTitleStep'; -import {BillStep} from '@hooks/useAddBillFunnel'; - -import {FixedButton, LabelInput} from '@components/Design'; - -import {BillInfo} from '../AddBillFunnel'; - -interface Props { - billInfo: BillInfo; - setBillInfo: React.Dispatch>; - setStep: React.Dispatch>; -} - -export const TitleStep = ({billInfo, setBillInfo, setStep}: Props) => { - const { - errorMessage, - handleTitleInputChange, - handleTitleInputEnter, - canSubmitTitleInput, - handlePrevStep, - handleNextStep, - } = useTitleStep({ - billInfo, - setBillInfo, - setStep, - }); - - return ( - <> -
    - - - - - -
    - - ๋‹ค์Œ์œผ๋กœ - - - ); -}; diff --git a/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx b/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx new file mode 100644 index 000000000..066165d6a --- /dev/null +++ b/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx @@ -0,0 +1,29 @@ +import {useLocation, useNavigate} from 'react-router-dom'; +import {FixedButton, MainLayout, Title, TopNav} from 'haengdong-design'; + +import {RunningDog} from '@components/Common/Logo'; + +import {ROUTER_URLS} from '@constants/routerUrls'; + +const CompleteCreateEventPage = () => { + const navigate = useNavigate(); + const location = useLocation(); + + const params = new URLSearchParams(location.search); + const eventId = params.get('eventId'); + + return ( + + + + <RunningDog /> + <FixedButton onClick={() => navigate(`${ROUTER_URLS.event}/${eventId}/admin`)}>๊ด€๋ฆฌ ํŽ˜์ด์ง€๋กœ ์ด๋™</FixedButton> + </MainLayout> + ); +}; + +export default CompleteCreateEventPage; diff --git a/client/src/pages/CreateEventPage/CompleteCreateEventStep.tsx b/client/src/pages/CreateEventPage/CompleteCreateEventStep.tsx deleted file mode 100644 index 34ee64661..000000000 --- a/client/src/pages/CreateEventPage/CompleteCreateEventStep.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import {useNavigate} from 'react-router-dom'; -import {css} from '@emotion/react'; - -import Top from '@components/Design/components/Top/Top'; - -import {RunningDog} from '@components/Logo'; - -import {FixedButton} from '@HDesign/index'; - -import {ROUTER_URLS} from '@constants/routerUrls'; - -type CompleteCreateEventStepProps = { - eventToken: string; -}; - -const CompleteCreateEventStep = ({eventToken}: CompleteCreateEventStepProps) => { - const navigate = useNavigate(); - - return ( - <div - css={css` - display: flex; - flex-direction: column; - gap: 3rem; - padding: 1rem; - `} - > - <Top> - <Top.Line text="ํ–‰์‚ฌ๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์–ด์š”!" emphasize={['ํ–‰์‚ฌ๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์–ด์š”!']} /> - <Top.Line text="๊ด€๋ฆฌ ํŽ˜์ด์ง€์—์„œ ์ •์‚ฐ์„ ์‹œ์ž‘ํ•˜์„ธ์š”" emphasize={['์ •์‚ฐ์„ ์‹œ์ž‘ํ•˜์„ธ์š”']} /> - </Top> - <RunningDog /> - <FixedButton onClick={() => navigate(`${ROUTER_URLS.event}/${eventToken}/admin`)}>๊ด€๋ฆฌ ํŽ˜์ด์ง€๋กœ ์ด๋™</FixedButton> - </div> - ); -}; - -export default CompleteCreateEventStep; diff --git a/client/src/pages/CreateEventPage/CreateEventFunnel.tsx b/client/src/pages/CreateEventPage/CreateEventFunnel.tsx deleted file mode 100644 index f21e62f23..000000000 --- a/client/src/pages/CreateEventPage/CreateEventFunnel.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import {useNavigate} from 'react-router-dom'; - -import useFunnel from '@hooks/useFunnel'; -import useCreateEventData from '@hooks/useCreateEventData'; - -import {MainLayout, TopNav} from '@components/Design'; - -import SetEventNameStep from './SetEventNameStep'; -import SetEventPasswordStep from './SetEventPasswordStep'; -import CompleteCreateEventStep from './CompleteCreateEventStep'; - -type CreateEventStep = 'eventName' | 'eventPassword' | 'complete'; -const STEP_SEQUENCE: CreateEventStep[] = ['eventName', 'eventPassword', 'complete']; - -const CreateEventFunnel = () => { - const navigate = useNavigate(); - const {moveToNextStep, moveToPrevStep, Funnel, step} = useFunnel({ - defaultStep: 'eventName', - stepList: STEP_SEQUENCE, - }); - - const {eventNameProps, eventToken, setEventToken} = useCreateEventData(); - - const handleBack = () => { - if (step === STEP_SEQUENCE[0]) { - navigate('/'); - } else { - moveToPrevStep(); - } - }; - - return ( - <MainLayout backgroundColor="white"> - <TopNav> - {step !== STEP_SEQUENCE[STEP_SEQUENCE.length - 1] && ( - <TopNav.Item displayName="๋’ค๋กœ๊ฐ€๊ธฐ" noEmphasis routePath="" onHandleRouteInFunnel={handleBack} /> - )} - </TopNav> - <Funnel step={step}> - <Funnel.Step name="eventName"> - <SetEventNameStep moveToNextStep={moveToNextStep} {...eventNameProps} /> - </Funnel.Step> - - <Funnel.Step name="eventPassword"> - <SetEventPasswordStep - moveToNextStep={moveToNextStep} - eventName={eventNameProps.eventName} - setEventToken={setEventToken} - /> - </Funnel.Step> - - <Funnel.Step name="complete"> - <CompleteCreateEventStep eventToken={eventToken} /> - </Funnel.Step> - </Funnel> - </MainLayout> - ); -}; - -export default CreateEventFunnel; diff --git a/client/src/pages/CreateEventPage/SetEventNamePage.tsx b/client/src/pages/CreateEventPage/SetEventNamePage.tsx new file mode 100644 index 000000000..ad68327d2 --- /dev/null +++ b/client/src/pages/CreateEventPage/SetEventNamePage.tsx @@ -0,0 +1,42 @@ +import {useNavigate} from 'react-router-dom'; +import {FixedButton, MainLayout, LabelInput, Title, TopNav, Back} from 'haengdong-design'; +import {css} from '@emotion/react'; + +import useSetEventNamePage from '@hooks/useSetEventNamePage'; + +import {ROUTER_URLS} from '@constants/routerUrls'; + +const SetEventNamePage = () => { + const navigate = useNavigate(); + const {eventName, errorMessage, canSubmit, handleEventNameChange} = useSetEventNamePage(); + + const submitEventName = (event: React.FormEvent<HTMLFormElement>) => { + event.preventDefault(); + + navigate(ROUTER_URLS.eventCreatePassword, {state: {eventName}}); + }; + + return ( + <MainLayout backgroundColor="white"> + <TopNav> + <Back /> + </TopNav> + <Title title="ํ–‰์‚ฌ ์ด๋ฆ„ ์ž…๋ ฅ" description="์‹œ์ž‘ํ•  ํ–‰์‚ฌ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”." /> + <form onSubmit={submitEventName} css={css({padding: '0 1rem'})}> + <LabelInput + labelText="ํ–‰์‚ฌ ์ด๋ฆ„" + errorText={errorMessage ?? ''} + value={eventName} + type="text" + placeholder="ํ–‰์‚ฌ ์ด๋ฆ„" + onChange={handleEventNameChange} + isError={!!errorMessage} + autoFocus + ></LabelInput> + <FixedButton disabled={!canSubmit}>๋‹ค์Œ</FixedButton> + </form> + </MainLayout> + ); +}; + +export default SetEventNamePage; diff --git a/client/src/pages/CreateEventPage/SetEventNameStep.tsx b/client/src/pages/CreateEventPage/SetEventNameStep.tsx deleted file mode 100644 index 924c4b79d..000000000 --- a/client/src/pages/CreateEventPage/SetEventNameStep.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import {css} from '@emotion/react'; - -import Top from '@components/Design/components/Top/Top'; - -import {UseSetEventNameStepReturnType} from '@hooks/useSetEventNameStep'; - -import {FixedButton, Flex, LabelInput} from '@HDesign/index'; - -type SetEventNamePageProps = UseSetEventNameStepReturnType & { - moveToNextStep: () => void; -}; - -const SetEventNameStep = ({ - eventName, - moveToNextStep, - errorMessage, - handleEventNameChange, - canSubmit, -}: SetEventNamePageProps) => { - const onSubmit = (event: React.FormEvent<HTMLFormElement>) => { - event.preventDefault(); - - moveToNextStep(); - }; - - return ( - <div - css={css` - display: flex; - flex-direction: column; - gap: 1rem; - padding: 1rem; - `} - > - <Top> - <Top.Line text="์ •์‚ฐ์„ ์‹œ์ž‘ํ•˜๋ ค๋Š”" /> - <Top.Line text="ํ–‰์‚ฌ์˜ ์ด๋ฆ„์€ ๋ฌด์—‡์ธ๊ฐ€์š”?" emphasize={['ํ–‰์‚ฌ์˜ ์ด๋ฆ„']} /> - </Top> - <form onSubmit={onSubmit}> - <LabelInput - labelText="ํ–‰์‚ฌ ์ด๋ฆ„" - errorText={errorMessage ?? ''} - value={eventName} - type="text" - placeholder="ํ–‰๋™๋Œ€์žฅ ์•ผ์œ ํšŒ" - onChange={handleEventNameChange} - isError={!!errorMessage} - autoFocus - /> - <FixedButton disabled={!canSubmit}>๋‹ค์Œ</FixedButton> - </form> - </div> - ); -}; - -export default SetEventNameStep; diff --git a/client/src/pages/CreateEventPage/SetEventPasswordPage.tsx b/client/src/pages/CreateEventPage/SetEventPasswordPage.tsx new file mode 100644 index 000000000..14fcdd75b --- /dev/null +++ b/client/src/pages/CreateEventPage/SetEventPasswordPage.tsx @@ -0,0 +1,41 @@ +import {FixedButton, MainLayout, LabelInput, Title, TopNav, Back} from 'haengdong-design'; + +import useSetEventPasswordPage from '@hooks/useSetEventPasswordPage'; + +import RULE from '@constants/rule'; +import {PASSWORD_LENGTH} from '@constants/password'; + +const SetEventPasswordPage = () => { + const {submitPassword, errorMessage, password, handleChange, canSubmit, isPostEventPending} = + useSetEventPasswordPage(); + + return ( + <MainLayout backgroundColor="white"> + <TopNav> + <Back /> + </TopNav> + <Title + title="ํ–‰์‚ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ ์„ค์ •" + description={`ํ–‰์‚ฌ ๊ด€๋ฆฌ์— ํ•„์š”ํ•œ ${PASSWORD_LENGTH} ์ž๋ฆฌ์˜ ์ˆซ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.`} + /> + <form onSubmit={submitPassword} style={{padding: '0 1rem'}}> + <LabelInput + labelText="๋น„๋ฐ€๋ฒˆํ˜ธ" + errorText={errorMessage} + value={password} + type="text" + maxLength={RULE.maxEventPasswordLength} + placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ" + onChange={handleChange} + isError={!!errorMessage} + autoFocus + /> + <FixedButton variants={isPostEventPending ? 'loading' : 'primary'} disabled={!canSubmit}> + ํ–‰๋™ ๊ฐœ์‹œ! + </FixedButton> + </form> + </MainLayout> + ); +}; + +export default SetEventPasswordPage; diff --git a/client/src/pages/CreateEventPage/SetEventPasswordStep.tsx b/client/src/pages/CreateEventPage/SetEventPasswordStep.tsx deleted file mode 100644 index 45370fd01..000000000 --- a/client/src/pages/CreateEventPage/SetEventPasswordStep.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import {css} from '@emotion/react'; - -import Top from '@components/Design/components/Top/Top'; - -import useSetEventPasswordStep, {UseSetEventPasswordStepReturnType} from '@hooks/useSetEventPasswordStep'; - -import {FixedButton, LabelInput} from '@HDesign/index'; - -import RULE from '@constants/rule'; - -type SetEventPasswordPageProps = { - eventName: string; - moveToNextStep: () => void; - setEventToken: (eventToken: string) => void; -}; - -const SetEventPasswordStep = ({eventName, moveToNextStep, setEventToken}: SetEventPasswordPageProps) => { - const {submitDataForPostEvent, errorMessage, password, handleChange, isPostEventPending, canSubmit} = - useSetEventPasswordStep(); - - const submit = async (event: React.FormEvent<HTMLFormElement>) => { - await submitDataForPostEvent({event, eventName, setEventToken}); - - moveToNextStep(); - }; - - return ( - <div - css={css` - display: flex; - flex-direction: column; - gap: 1rem; - padding: 1rem; - `} - > - <Top> - <Top.Line - text={`๊ด€๋ฆฌ์— ํ•„์š”ํ•œ ${RULE.maxEventPasswordLength}์ž๋ฆฌ ์ˆซ์ž`} - emphasize={[`${RULE.maxEventPasswordLength}์ž๋ฆฌ ์ˆซ์ž`]} - /> - <Top.Line text="๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋ฌด์—‡์œผ๋กœ ํ• ๊นŒ์š”?" emphasize={['๋น„๋ฐ€๋ฒˆํ˜ธ']} /> - </Top> - <form onSubmit={submit}> - <LabelInput - labelText="๋น„๋ฐ€๋ฒˆํ˜ธ" - errorText={errorMessage} - value={password} - type="text" - maxLength={RULE.maxEventPasswordLength} - placeholder="1234" - onChange={handleChange} - isError={!!errorMessage} - autoFocus - /> - {/* ๊ฐ€์ƒ ํ‚คํŒจ๋“œ ์ ์šฉ ์˜ˆ์ • */} - <FixedButton type="submit" variants={isPostEventPending ? 'loading' : 'primary'} disabled={!canSubmit}> - ํ–‰๋™ ๊ฐœ์‹œ! - </FixedButton> - </form> - </div> - ); -}; - -export default SetEventPasswordStep; diff --git a/client/src/pages/CreateEventPage/index.ts b/client/src/pages/CreateEventPage/index.ts index 8d5867dc6..6d3d6c808 100644 --- a/client/src/pages/CreateEventPage/index.ts +++ b/client/src/pages/CreateEventPage/index.ts @@ -1,3 +1,3 @@ -export {default as SetEventNameStep} from './SetEventNameStep'; -export {default as SetEventPasswordStep} from './SetEventPasswordStep'; -export {default as CompleteCreateEventStep} from './CompleteCreateEventStep'; +export {default as SetEventNamePage} from './SetEventNamePage'; +export {default as SetEventPasswordPage} from './SetEventPasswordPage'; +export {default as CompleteCreateEventPage} from './CompleteCreateEventPage'; diff --git a/client/src/pages/EditBillPage/EditBillPage.tsx b/client/src/pages/EditBillPage/EditBillPage.tsx deleted file mode 100644 index 75a02d755..000000000 --- a/client/src/pages/EditBillPage/EditBillPage.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import {css} from '@emotion/react'; - -import AmountInput from '@components/AmountInput/AmountInput'; -import BillDetails from '@components/BillDetails/BillDetails'; -import NumberKeyboardBottomSheet from '@components/Design/components/NumberKeyboard/NumberKeyboardBottomSheet'; -import Top from '@components/Design/components/Top/Top'; - -import useEditBillPage from '@hooks/useEditBillPage'; - -import {FixedButton, Flex, MainLayout, TopNav} from '@components/Design'; - -const EditBillPage = () => { - const { - newBill, - newBillDetails, - billDetailsRef, - handleChangeBillTitle, - handleChangeBillPrice, - handleChangeBillDetails, - handleClickBillDetailInput, - handleClickDelete, - handleClickUpdate, - isPendingUpdate, - canSubmit, - keyboardInitialValue, - keyboardMaxPrice, - keyboardTargetId, - setKeyboardTargetId, - } = useEditBillPage(); - - return ( - <MainLayout backgroundColor="white"> - <TopNav> - <TopNav.Item displayName="๋’ค๋กœ๊ฐ€๊ธฐ" noEmphasis routePath="-1" /> - </TopNav> - <div - css={css` - display: flex; - flex-direction: column; - gap: 1rem; - padding: 1rem; - `} - > - <Top> - <Flex justifyContent="spaceBetween"> - <Top.EditableLine value={newBill.title} onChange={handleChangeBillTitle} /> - <Top.Line text="์—์„œ" /> - </Flex> - </Top> - <AmountInput - value={newBill.price.toLocaleString('ko-kr')} - onClick={() => handleClickBillDetailInput(0)} - underlined={true} - activated={keyboardTargetId === 0} - /> - - <BillDetails - ref={billDetailsRef} - billDetails={newBillDetails} - onClickInput={handleClickBillDetailInput} - activatedId={keyboardTargetId as number} - /> - </div> - {keyboardTargetId !== null && ( - <div - css={css` - height: 416px; - `} - content=" " - /> - )} - <FixedButton - disabled={!canSubmit} - onClick={handleClickUpdate} - onDeleteClick={handleClickDelete} - variants={isPendingUpdate() ? 'loading' : 'primary'} - > - ์ˆ˜์ •์™„๋ฃŒ - </FixedButton> - <NumberKeyboardBottomSheet - type="amount" - maxNumber={keyboardMaxPrice} - initialValue={keyboardInitialValue} - onChange={ - keyboardTargetId === 0 - ? handleChangeBillPrice - : (value: string) => handleChangeBillDetails({value, keyboardTargetId: keyboardTargetId ?? 0}) - } - isOpened={keyboardTargetId !== null} - onClose={() => setKeyboardTargetId(null)} - /> - </MainLayout> - ); -}; - -export default EditBillPage; diff --git a/client/src/pages/ErrorPage/ErrorPage.tsx b/client/src/pages/ErrorPage/ErrorPage.tsx index 92810e668..31ef8c81f 100644 --- a/client/src/pages/ErrorPage/ErrorPage.tsx +++ b/client/src/pages/ErrorPage/ErrorPage.tsx @@ -1,13 +1,12 @@ -import Top from '@components/Design/components/Top/Top'; - -import {MainLayout} from '@HDesign/index'; +import {MainLayout, Title} from 'haengdong-design'; const ErrorPage = () => { return ( <MainLayout> - <Top> - <Top.Line text="์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค." emphasize={['์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค.']} /> - </Top> + <Title + title="์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค." + description="์˜ค๋ฅ˜๊ฐ€ ๋‚œ ์ƒํ™ฉ์— ๋Œ€ํ•ด haengdongdj@gmail.com ๋กœ ์—ฐ๋ฝ์ฃผ์‹œ๋ฉด ์†Œ์ •์˜ ์ƒํ’ˆ์„ ๋“œ๋ฆฝ๋‹ˆ๋‹ค." + /> </MainLayout> ); }; diff --git a/client/src/pages/EventPage/AdminPage/AdminPage.style.ts b/client/src/pages/EventPage/AdminPage/AdminPage.style.ts index 830ec74a2..cf6bb0042 100644 --- a/client/src/pages/EventPage/AdminPage/AdminPage.style.ts +++ b/client/src/pages/EventPage/AdminPage/AdminPage.style.ts @@ -4,8 +4,7 @@ export const receiptStyle = () => css({ display: 'flex', flexDirection: 'column', - gap: '0.5rem', - paddingInline: '1rem', + gap: '1rem', paddingBottom: '2rem', }); diff --git a/client/src/pages/EventPage/AdminPage/AdminPage.tsx b/client/src/pages/EventPage/AdminPage/AdminPage.tsx index c69170897..79deeac7a 100644 --- a/client/src/pages/EventPage/AdminPage/AdminPage.tsx +++ b/client/src/pages/EventPage/AdminPage/AdminPage.tsx @@ -1,59 +1,89 @@ -import {useEffect} from 'react'; -import {useNavigate, useOutletContext} from 'react-router-dom'; +import {useEffect, useState} from 'react'; +import {Title, FixedButton, ListButton, Button} from 'haengdong-design'; +import {useOutletContext} from 'react-router-dom'; -import StepList from '@components/StepList/Steps'; -import useRequestPostAuthenticate from '@hooks/queries/auth/useRequestPostAuthentication'; -import useRequestGetSteps from '@hooks/queries/step/useRequestGetSteps'; +import StepList from '@components/StepList/StepList'; +import {ModalBasedOnMemberCount, SetAllMemberListModal} from '@components/Modal/index'; +import useRequestGetAllMemberList from '@hooks/queries/useRequestGetAllMemberList'; +import useRequestPostAuthenticate from '@hooks/queries/useRequestPostAuthentication'; import {useTotalExpenseAmountStore} from '@store/totalExpenseAmountStore'; -import {Title, Button, Dropdown, DropdownButton} from '@HDesign/index'; - -import getEventIdByUrl from '@utils/getEventIdByUrl'; - import {EventPageContextProps} from '../EventPageLayout'; -import {receiptStyle} from './AdminPage.style'; +import {receiptStyle, titleAndListButtonContainerStyle, buttonGroupStyle} from './AdminPage.style'; const AdminPage = () => { - const navigate = useNavigate(); - const eventId = getEventIdByUrl(); - const {isAdmin, eventName} = useOutletContext<EventPageContextProps>(); + const [isOpenFixedButtonBottomSheet, setIsOpenFixedButtonBottomSheet] = useState(false); + const [isOpenAllMemberListButton, setIsOpenAllMemberListButton] = useState(false); + const [isAddEditableItem, setIsAddEditableItem] = useState(false); + + const {eventName} = useOutletContext<EventPageContextProps>(); + const {data: allMemberListData} = useRequestGetAllMemberList(); + const allMemberList = allMemberListData?.memberNames ?? []; const {totalExpenseAmount} = useTotalExpenseAmountStore(); - const {steps} = useRequestGetSteps(); - const {postAuthenticate} = useRequestPostAuthenticate(); + const {mutate: postAuthentication} = useRequestPostAuthenticate(); useEffect(() => { - postAuthenticate(); - }, [postAuthenticate]); + postAuthentication(); + }, [postAuthentication]); - const navigateAccountInputPage = () => { - navigate(`/event/${eventId}/admin/edit`); + const handleOpenAllMemberListButton = () => { + setIsOpenFixedButtonBottomSheet(prev => !prev); + setIsOpenAllMemberListButton(prev => !prev); }; - const navigateEventMemberManage = () => { - navigate(`/event/${eventId}/admin/member`); + const getTitleDescriptionByInitialMemberSetting = () => { + return allMemberList.length > 0 + ? `์ง€์ถœ ๋‚ด์—ญ ๋ฐ ์ธ์› ๋ณ€๋™์„ ์ถ”๊ฐ€ํ•ด ์ฃผ์„ธ์š”. + ์ธ์› ๋ณ€๋™์„ ๊ธฐ์ค€์œผ๋กœ ๋ช‡ ์ฐจ์ธ์ง€ ๋‚˜๋‰˜์–ด์ ธ์š”.` + : 'โ€œ์‹œ์ž‘ ์ธ์› ์ถ”๊ฐ€โ€ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ํ–‰์‚ฌ์˜ ์‹œ์ž‘๋ถ€ํ„ฐ ์ฐธ์—ฌํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.'; }; return ( - <section css={receiptStyle}> - <Title - title={eventName} - amount={totalExpenseAmount} - dropdown={ - <Dropdown> - <DropdownButton text="์ „์ฒด ์ฐธ์—ฌ์ž ๊ด€๋ฆฌ" onClick={navigateEventMemberManage} /> - <DropdownButton text="๊ณ„์ขŒ๋ฒˆํ˜ธ ์ž…๋ ฅํ•˜๊ธฐ" onClick={navigateAccountInputPage} /> - </Dropdown> - } - /> - <StepList data={steps ?? []} isAdmin={isAdmin} /> - <Button size="medium" onClick={() => navigate(`/event/${eventId}/add-bill`)} style={{width: '100%'}}> - ์ง€์ถœ๋‚ด์—ญ ์ถ”๊ฐ€ํ•˜๊ธฐ - </Button> - </section> + <> + <div css={titleAndListButtonContainerStyle}> + <Title title={eventName} description={getTitleDescriptionByInitialMemberSetting()} price={totalExpenseAmount} /> + {allMemberList.length !== 0 && ( + <ListButton + prefix="์ „์ฒด ์ฐธ์—ฌ์ž" + suffix={`${allMemberList.length}๋ช…`} + onClick={handleOpenAllMemberListButton} + /> + )} + </div> + <section css={receiptStyle}> + <StepList isAddEditableItem={isAddEditableItem} setIsAddEditableItem={setIsAddEditableItem} /> + {allMemberList.length === 0 ? ( + <FixedButton children={'์‹œ์ž‘์ธ์› ์ถ”๊ฐ€ํ•˜๊ธฐ'} onClick={() => setIsOpenFixedButtonBottomSheet(prev => !prev)} /> + ) : ( + <div css={buttonGroupStyle}> + <Button + size="medium" + variants="tertiary" + style={{width: '100%'}} + onClick={() => setIsOpenFixedButtonBottomSheet(prev => !prev)} + > + ์ธ์› ๋ณ€๋™ ์ถ”๊ฐ€ + </Button> + <Button size="medium" onClick={() => setIsAddEditableItem(true)} style={{width: '100%'}}> + ์ง€์ถœ ๋‚ด์—ญ ์ถ”๊ฐ€ + </Button> + </div> + )} + {isOpenFixedButtonBottomSheet && ( + <ModalBasedOnMemberCount + allMemberList={allMemberList} + setIsOpenBottomSheet={setIsOpenFixedButtonBottomSheet} + isOpenBottomSheet={isOpenFixedButtonBottomSheet} + isOpenAllMemberListButton={isOpenAllMemberListButton} + setIsOpenAllMemberListButton={setIsOpenAllMemberListButton} + /> + )} + </section> + </> ); }; diff --git a/client/src/pages/EventPage/AdminPage/EventLoginPage.tsx b/client/src/pages/EventPage/AdminPage/EventLoginPage.tsx index 03e189fc1..741dca3eb 100644 --- a/client/src/pages/EventPage/AdminPage/EventLoginPage.tsx +++ b/client/src/pages/EventPage/AdminPage/EventLoginPage.tsx @@ -1,33 +1,20 @@ -import {css} from '@emotion/react'; - -import Top from '@components/Design/components/Top/Top'; +import {FixedButton, LabelInput, Title} from 'haengdong-design'; import useEventLogin from '@hooks/useEventLogin'; -import {FixedButton, LabelInput} from '@HDesign/index'; - import RULE from '@constants/rule'; +import {PASSWORD_LENGTH} from '@constants/password'; const EventLoginPage = () => { const {password, errorMessage, handleChange, canSubmit, submitPassword} = useEventLogin(); return ( - <div - css={css` - display: flex; - flex-direction: column; - gap: 1rem; - padding: 1rem; - `} - > - <Top> - <Top.Line - text={`ํ–‰์‚ฌ ์ƒ์„ฑ ์‹œ ์„ค์ •ํ•œ ${RULE.maxEventPasswordLength}์ž๋ฆฌ`} - emphasize={[`${RULE.maxEventPasswordLength}์ž๋ฆฌ`]} - /> - <Top.Line text="์ˆซ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”." emphasize={['๋น„๋ฐ€๋ฒˆํ˜ธ']} /> - </Top> - <form onSubmit={submitPassword}> + <> + <Title + title="ํ–‰์‚ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ" + description={`๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด์„  ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ•„์š”ํ•ด์š”. ํ–‰์‚ฌ ์ƒ์„ฑ ์‹œ ์„ค์ •ํ•œ ${PASSWORD_LENGTH} ์ž๋ฆฌ์˜ ์ˆซ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.`} + /> + <form onSubmit={submitPassword} style={{padding: '0 1rem'}}> <LabelInput labelText="๋น„๋ฐ€๋ฒˆํ˜ธ" errorText={errorMessage} @@ -41,7 +28,7 @@ const EventLoginPage = () => { ></LabelInput> <FixedButton disabled={!canSubmit}>๊ด€๋ฆฌ ํŽ˜์ด์ง€๋กœ</FixedButton> </form> - </div> + </> ); }; diff --git a/client/src/pages/EventPage/AdminPage/EventMember.style.ts b/client/src/pages/EventPage/AdminPage/EventMember.style.ts deleted file mode 100644 index f59f288bd..000000000 --- a/client/src/pages/EventPage/AdminPage/EventMember.style.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@components/Design/theme/theme.type'; -import TYPOGRAPHY from '@components/Design/token/typography'; - -export const eventMemberStyle = () => - css({ - padding: '0 1rem', - }); - -export const memberList = () => - css({ - display: 'flex', - flexDirection: 'column', - gap: '0.5rem', - padding: '0 0.5rem', - marginTop: '1rem', - height: 'inherit', - marginBottom: '100px', - }); - -export const noneReports = () => - css({ - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', - height: 'inherit', - }); - -export const eventMember = () => - css({ - display: 'flex', - alignItems: 'center', - gap: '0.5rem', - padding: '0.5rem 0', - width: 'inherit', - justifyContent: 'space-between', - }); - -export const memberEditInput = (theme: Theme) => - css({ - input: { - width: '100%', - }, - width: '6.125rem', - display: 'flex', - alignItems: 'center', - justifyContent: 'space-between', - borderBottom: `1px solid ${theme.colors.tertiary}`, - ...TYPOGRAPHY.bodyBold, - - '&:has(input:focus)': { - borderBottom: `1px solid ${theme.colors.primary}`, - }, - }); diff --git a/client/src/pages/EventPage/AdminPage/EventMember.tsx b/client/src/pages/EventPage/AdminPage/EventMember.tsx deleted file mode 100644 index cdeaa8d40..000000000 --- a/client/src/pages/EventPage/AdminPage/EventMember.tsx +++ /dev/null @@ -1,94 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {Report} from 'types/serviceType'; - -import useEventMember from '@hooks/useEventMember'; - -import {MainLayout, TopNav, Top, Amount, DepositToggle, Icon, IconButton, FixedButton, Text} from '@components/Design'; -import {useTheme} from '@components/Design'; - -import {eventMemberStyle, memberList, eventMember, memberEditInput, noneReports} from './EventMember.style'; - -const EventMember = () => { - const {reports, canSubmit, changeMemberName, handleDeleteMember, updateMembersOnServer, toggleDepositStatus} = - useEventMember(); - - return ( - <MainLayout backgroundColor="white"> - <TopNav> - <TopNav.Item displayName="๋’ค๋กœ๊ฐ€๊ธฐ" noEmphasis routePath="-1" /> - </TopNav> - <section css={eventMemberStyle}> - <Top> - <Top.Line text="์ „์ฒด ์ฐธ์—ฌ์ž ๊ด€๋ฆฌ" emphasize={['์ „์ฒด ์ฐธ์—ฌ์ž ๊ด€๋ฆฌ']}></Top.Line> - </Top> - <div css={memberList}> - {reports.length === 0 ? ( - <div css={noneReports}> - <Text size="bodyBold">์ฐธ์—ฌ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์•„์š”!</Text> - <Text size="body" textColor="gray"> - ์ง€์ถœ๋‚ด์—ญ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์ฐธ์—ฌ์ž๊ฐ€ ์ƒ์„ฑ๋ผ์š”. - </Text> - </div> - ) : ( - reports.map(member => { - return ( - <Member - key={member.memberId} - member={member} - changeMemberName={changeMemberName} - handleDeleteMember={handleDeleteMember} - toggleDepositStatus={toggleDepositStatus} - /> - ); - }) - )} - </div> - {reports.length === 0 ? ( - <></> - ) : ( - <FixedButton disabled={!canSubmit} onClick={updateMembersOnServer}> - ์ˆ˜์ •์™„๋ฃŒ - </FixedButton> - )} - </section> - </MainLayout> - ); -}; - -interface MemberProps { - member: Report; - changeMemberName: (memberId: number, newName: string) => void; - handleDeleteMember: (memberId: number) => void; - toggleDepositStatus: (memberId: number) => void; -} - -const Member = ({member, changeMemberName, handleDeleteMember, toggleDepositStatus}: MemberProps) => { - const {theme} = useTheme(); - - const handleChangeName = (e: React.ChangeEvent<HTMLInputElement>) => { - changeMemberName(member.memberId, e.target.value); - }; - - return ( - <div css={eventMember} id={`${member.memberId}`}> - <div css={memberEditInput(theme)}> - <input type="text" value={member.memberName} onChange={e => handleChangeName(e)} /> - <Icon iconType="pencilMini" /> - </div> - <div style={{display: 'flex', flexDirection: 'row', gap: '0.5rem'}}> - <Amount amount={member.price} /> - <DepositToggle isDeposit={member.isDeposited} onToggle={() => toggleDepositStatus(member.memberId)} /> - <IconButton - size="small" - variants="tertiary" - css={{width: '23px', height: '23px', borderRadius: '0.375rem'}} - onClick={() => handleDeleteMember(member.memberId)} - > - <Icon iconType="trashMini" /> - </IconButton> - </div> - </div> - ); -}; - -export default EventMember; diff --git a/client/src/pages/EventPage/EventPageFallback/BillEmptyFallback/index.tsx b/client/src/pages/EventPage/EventPageFallback/BillEmptyFallback/index.tsx deleted file mode 100644 index 4e8c0d7d7..000000000 --- a/client/src/pages/EventPage/EventPageFallback/BillEmptyFallback/index.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import {Flex, Text} from '@components/Design'; - -import FALLBACK_TEXT from '../fallbackText'; - -const BillEmptyFallback = () => { - return ( - <Flex flexDirection="column" justifyContent="center" alignItems="center" gap="1.5rem" width="100%" height="20rem"> - <Text size="subTitle">{FALLBACK_TEXT.billEmptyTitle}</Text> - <Text size="body" style={{textAlign: 'center'}}> - {FALLBACK_TEXT.billEmptyHome} - </Text> - </Flex> - ); -}; - -export default BillEmptyFallback; diff --git a/client/src/pages/EventPage/EventPageFallback/fallbackText.ts b/client/src/pages/EventPage/EventPageFallback/fallbackText.ts deleted file mode 100644 index 6238264aa..000000000 --- a/client/src/pages/EventPage/EventPageFallback/fallbackText.ts +++ /dev/null @@ -1,7 +0,0 @@ -const FALLBACK_TEXT = { - billEmptyTitle: 'ํ–‰์‚ฌ๊ฐ€ ์‹œ์ž‘๋˜์ง€ ์•Š์•˜์–ด์š”', - billEmptyHome: `์ฃผ์ตœ์ž๊ฐ€ ์•„์ง ์ง€์ถœ ๋‚ด์—ญ์„ -๋“ฑ๋กํ•˜์ง€ ์•Š์•˜์–ด์š”.`, -} as const; - -export default FALLBACK_TEXT; diff --git a/client/src/pages/EventPage/EventPageLayout.tsx b/client/src/pages/EventPage/EventPageLayout.tsx index 2fcf0d682..6f00c23f1 100644 --- a/client/src/pages/EventPage/EventPageLayout.tsx +++ b/client/src/pages/EventPage/EventPageLayout.tsx @@ -1,39 +1,62 @@ -import type {Event} from 'types/serviceType'; +import {MainLayout, TopNav, Switch, Button} from 'haengdong-design'; +import {Outlet, useMatch} from 'react-router-dom'; +import CopyToClipboard from 'react-copy-to-clipboard'; -import {Outlet} from 'react-router-dom'; +import {useToast} from '@hooks/useToast/useToast'; +import useRequestGetEventName from '@hooks/queries/useRequestGetEventName'; -import useEventPageLayout from '@hooks/useEventPageLayout'; +import useNavSwitch from '@hooks/useNavSwitch'; -import {ShareEventButton} from '@components/ShareEventButton'; +import getEventIdByUrl from '@utils/getEventIdByUrl'; +import getEventPageUrlByEnvironment from '@utils/getEventPageUrlByEnvironment'; -import {Flex, Icon, IconButton, MainLayout, TopNav} from '@HDesign/index'; +import {ROUTER_URLS} from '@constants/routerUrls'; -export type EventPageContextProps = Event & { +export type EventPageContextProps = { isAdmin: boolean; + eventName: string; }; const EventPageLayout = () => { - const {isAdmin, isLoginPage, eventOutline} = useEventPageLayout(); + const {nav, paths, onChange} = useNavSwitch(); + const {data} = useRequestGetEventName(); + const eventName = data?.eventName ?? ''; + const eventId = getEventIdByUrl(); + + const isAdmin = useMatch(ROUTER_URLS.eventManage) !== null; + const isLoginPage = useMatch(ROUTER_URLS.eventLogin) !== null; const outletContext: EventPageContextProps = { isAdmin, - ...eventOutline, + eventName, }; + const {showToast} = useToast(); + const url = getEventPageUrlByEnvironment(eventId, 'home'); + return ( <MainLayout backgroundColor="gray"> - <Flex justifyContent="spaceBetween" alignItems="center"> - <TopNav> - <TopNav.Item routePath="/"> - <IconButton variants="none"> - <Icon iconType="heundeut" /> - </IconButton> - </TopNav.Item> - <TopNav.Item displayName="ํ™ˆ" routePath="/home" /> - <TopNav.Item displayName="๊ด€๋ฆฌ" routePath="/admin" /> - </TopNav> - {!isLoginPage && <ShareEventButton eventOutline={eventOutline} />} - </Flex> + <TopNav> + <Switch value={nav} values={paths} onChange={onChange} /> + {!isLoginPage && ( + <CopyToClipboard + text={`[ํ–‰๋™๋Œ€์žฅ]\n"${eventName}"์— ๋Œ€ํ•œ ์ •์‚ฐ์„ ์‹œ์ž‘ํ• ๊ฒŒ์š”:)\n์•„๋ž˜ ๋งํฌ์— ์ ‘์†ํ•ด์„œ ์ •์‚ฐ ๋‚ด์—ญ์„ ํ™•์ธํ•ด ์ฃผ์„ธ์š”!\n${url}`} + onCopy={() => + showToast({ + showingTime: 3000, + message: '๋งํฌ๊ฐ€ ๋ณต์‚ฌ๋˜์—ˆ์–ด์š” :) \n์ฐธ์—ฌ์ž๋“ค์—๊ฒŒ ๋งํฌ๋ฅผ ๊ณต์œ ํ•ด ์ฃผ์„ธ์š”!', + type: 'confirm', + position: 'bottom', + bottom: '8rem', + }) + } + > + <Button size="small" variants="secondary"> + ์ •์‚ฐ ์ดˆ๋Œ€ํ•˜๊ธฐ + </Button> + </CopyToClipboard> + )} + </TopNav> <Outlet context={outletContext} /> </MainLayout> ); diff --git a/client/src/pages/EventPage/HomePage/HomePage.style.ts b/client/src/pages/EventPage/HomePage/HomePage.style.ts deleted file mode 100644 index d02747cb2..000000000 --- a/client/src/pages/EventPage/HomePage/HomePage.style.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {css} from '@emotion/react'; - -export const receiptStyle = css({ - display: 'flex', - flexDirection: 'column', - gap: '0.5rem', - paddingInline: '1rem', - paddingBottom: '2rem', -}); diff --git a/client/src/pages/EventPage/HomePage/HomePage.tsx b/client/src/pages/EventPage/HomePage/HomePage.tsx index 1876327bf..72fc77cb9 100644 --- a/client/src/pages/EventPage/HomePage/HomePage.tsx +++ b/client/src/pages/EventPage/HomePage/HomePage.tsx @@ -1,28 +1,23 @@ -import type {EventPageContextProps} from '../EventPageLayout'; - +import {Tab, Tabs, Title} from 'haengdong-design'; import {useOutletContext} from 'react-router-dom'; -import StepList from '@components/StepList/Steps'; -import useRequestGetSteps from '@hooks/queries/step/useRequestGetSteps'; -import Reports from '@components/Reports/Reports'; +import MemberReportList from '@components/MemberReportList/MemberReportList'; +import StepList from '@components/StepList/StepList'; import {useTotalExpenseAmountStore} from '@store/totalExpenseAmountStore'; -import {Tab, Tabs, Title} from '@HDesign/index'; - -import {receiptStyle} from './HomePage.style'; +import {EventPageContextProps} from '../EventPageLayout'; const HomePage = () => { - const {isAdmin, eventName} = useOutletContext<EventPageContextProps>(); - const {steps} = useRequestGetSteps(); + const {eventName} = useOutletContext<EventPageContextProps>(); const {totalExpenseAmount} = useTotalExpenseAmountStore(); return ( - <div css={receiptStyle}> - <Title title={eventName} amount={totalExpenseAmount} /> - <Tabs> - <Tab label="์ฐธ์—ฌ์ž ๋ณ„ ์ •์‚ฐ" content={<Reports />} /> - <Tab label="์ „์ฒด ์ง€์ถœ ๋‚ด์—ญ" content={<StepList data={steps ?? []} isAdmin={isAdmin} />} /> + <div style={{paddingBottom: '2rem'}}> + <Title title={eventName} price={totalExpenseAmount} /> + <Tabs tabsContainerStyle={{gap: '1rem'}}> + <Tab label="์ „์ฒด ์ง€์ถœ ๋‚ด์—ญ" content={<StepList />} /> + <Tab label="์ฐธ์—ฌ์ž ๋ณ„ ๋‚ด์—ญ" content={<MemberReportList />} /> </Tabs> </div> ); diff --git a/client/src/pages/MainPage/MainPage.tsx b/client/src/pages/MainPage/MainPage.tsx index 50cae98b8..d3a1cd079 100644 --- a/client/src/pages/MainPage/MainPage.tsx +++ b/client/src/pages/MainPage/MainPage.tsx @@ -1,11 +1,11 @@ -import {Flex, MainLayout} from '@HDesign/index'; +import {MainLayout} from 'haengdong-design'; import Nav from './Nav/Nav'; import MainSection from './Section/MainSection'; import DescriptionSection from './Section/DescriptionSection'; import AddBillSection from './Section/AddBillSection'; import AddMemberSection from './Section/AddMemberSection'; -import ReportSection from './Section/ReportSection'; +import MemberReportSection from './Section/MemberReportSection'; const MainPage = () => { return ( @@ -15,7 +15,7 @@ const MainPage = () => { <DescriptionSection /> <AddBillSection /> <AddMemberSection /> - <ReportSection /> + <MemberReportSection /> </MainLayout> ); }; diff --git a/client/src/pages/MainPage/Nav/Nav.style.ts b/client/src/pages/MainPage/Nav/Nav.style.ts index 89589e825..58cf1cb86 100644 --- a/client/src/pages/MainPage/Nav/Nav.style.ts +++ b/client/src/pages/MainPage/Nav/Nav.style.ts @@ -1,22 +1,19 @@ import {css} from '@emotion/react'; -import {Theme} from '@components/Design/theme/theme.type'; - -export const navStyle = (theme: Theme) => - css({ - position: 'fixed', - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - padding: '1rem', +export const navStyle = css({ + position: 'fixed', + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '1rem', - top: '0', - width: '100%', - maxWidth: '768px', - zIndex: theme.zIndex.navBackgroundColor, - height: '4rem', - backgroundColor: 'white', - }); + top: '0', + width: '100%', + maxWidth: '768px', + zIndex: '20', + height: '4rem', + backgroundColor: 'white', +}); export const logoStyle = css({ display: 'flex', diff --git a/client/src/pages/MainPage/Nav/Nav.tsx b/client/src/pages/MainPage/Nav/Nav.tsx index 2ca0cfb4d..ec4d745c9 100644 --- a/client/src/pages/MainPage/Nav/Nav.tsx +++ b/client/src/pages/MainPage/Nav/Nav.tsx @@ -1,32 +1,23 @@ +import {Button, Flex, Text} from 'haengdong-design'; import {useNavigate} from 'react-router-dom'; -import {useTheme} from '@theme/HDesignProvider'; - -import {Button, Flex, Text, Icon, TopNav, IconButton} from '@HDesign/index'; +import Heundeut from '@assets/image/heundeut.svg'; import {ROUTER_URLS} from '@constants/routerUrls'; +import {logoStyle, navStyle} from './Nav.style'; + const Nav = () => { - const {theme} = useTheme(); const navigate = useNavigate(); return ( - <header style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', height: '37px'}}> - <TopNav> - <TopNav.Item routePath="/"> - <IconButton variants="none"> - <Icon iconType="heundeut" /> - </IconButton> - </TopNav.Item> - <TopNav.Item routePath="/"> + <header css={navStyle}> + <Flex gap="0.5rem"> + <Heundeut /> + <div css={logoStyle}> <Text size="subTitle">ํ–‰๋™๋Œ€์žฅ</Text> - </TopNav.Item> - </TopNav> - <Button - size="medium" - variants="tertiary" - onClick={() => navigate(ROUTER_URLS.createEvent)} - style={{marginRight: '1rem'}} - > + </div> + </Flex> + <Button size="medium" variants="tertiary" onClick={() => navigate(ROUTER_URLS.eventCreateName)}> ์ •์‚ฐ ์‹œ์ž‘ํ•˜๊ธฐ </Button> </header> diff --git a/client/src/pages/MainPage/Section/AddBillSection.tsx b/client/src/pages/MainPage/Section/AddBillSection.tsx index ca2fe1f34..ecf7dd90d 100644 --- a/client/src/pages/MainPage/Section/AddBillSection.tsx +++ b/client/src/pages/MainPage/Section/AddBillSection.tsx @@ -1,9 +1,8 @@ import {css} from '@emotion/react'; +import {Text} from 'haengdong-design'; import AddBillMockup from '@assets/image/addBillMockup.svg'; -import {Text} from '@HDesign/index'; - const AddBillSection = () => { return ( <div diff --git a/client/src/pages/MainPage/Section/AddMemberSection.tsx b/client/src/pages/MainPage/Section/AddMemberSection.tsx index a7ff92539..ae6e7d1fc 100644 --- a/client/src/pages/MainPage/Section/AddMemberSection.tsx +++ b/client/src/pages/MainPage/Section/AddMemberSection.tsx @@ -1,10 +1,9 @@ import {css} from '@emotion/react'; +import {Text} from 'haengdong-design'; +import {useTheme} from 'haengdong-design/dist/theme/HDesignProvider'; import AddMemberMockup from '@assets/image/addMemberMockup.svg'; -import {Text} from '@HDesign/index'; -import {useTheme} from '@HDesign/index'; - const AddMemberSection = () => { const {theme} = useTheme(); return ( diff --git a/client/src/pages/MainPage/Section/DescriptionSection.tsx b/client/src/pages/MainPage/Section/DescriptionSection.tsx index f53e88cf9..193cfe465 100644 --- a/client/src/pages/MainPage/Section/DescriptionSection.tsx +++ b/client/src/pages/MainPage/Section/DescriptionSection.tsx @@ -1,6 +1,6 @@ import {css} from '@emotion/react'; - -import {Text, useTheme} from '@HDesign/index'; +import {Text} from 'haengdong-design'; +import {useTheme} from 'haengdong-design/dist/theme/HDesignProvider'; const DescriptionSection = () => { const {theme} = useTheme(); diff --git a/client/src/pages/MainPage/Section/MainSection.tsx b/client/src/pages/MainPage/Section/MainSection.tsx index 3be031978..4bbeb7340 100644 --- a/client/src/pages/MainPage/Section/MainSection.tsx +++ b/client/src/pages/MainPage/Section/MainSection.tsx @@ -1,17 +1,14 @@ import {css, keyframes} from '@emotion/react'; +import {Button, Text} from 'haengdong-design'; import {useNavigate} from 'react-router-dom'; +import {StandingDog} from '@components/Common/Logo'; import ChevronDown from '@assets/image/chevronDownLarge.svg'; -import {StandingDog} from '@components/Logo'; - -import {Button, Text} from '@HDesign/index'; - import {ROUTER_URLS} from '@constants/routerUrls'; const MainSection = () => { const navigate = useNavigate(); - return ( <div css={css({ @@ -41,7 +38,7 @@ const MainSection = () => { <Text css={animateWithDelay(1)} style={{textAlign: 'center'}} size="title">{`ํ–‰๋™๋Œ€์žฅ์„ ํ†ตํ•ด ๊ฐ„ํŽธํ•˜๊ฒŒ ์ •์‚ฐํ•˜์„ธ์š” `}</Text> - <Button css={animateWithDelay(2)} size="large" onClick={() => navigate(ROUTER_URLS.createEvent)}> + <Button css={animateWithDelay(2)} size="large" onClick={() => navigate(ROUTER_URLS.eventCreateName)}> ์ •์‚ฐ ์‹œ์ž‘ํ•˜๊ธฐ </Button> </div> diff --git a/client/src/pages/MainPage/Section/ReportSection.tsx b/client/src/pages/MainPage/Section/MemberReportSection.tsx similarity index 86% rename from client/src/pages/MainPage/Section/ReportSection.tsx rename to client/src/pages/MainPage/Section/MemberReportSection.tsx index 452365ea2..69871e1c9 100644 --- a/client/src/pages/MainPage/Section/ReportSection.tsx +++ b/client/src/pages/MainPage/Section/MemberReportSection.tsx @@ -1,10 +1,9 @@ import {css} from '@emotion/react'; +import {Text} from 'haengdong-design'; import MemberReportMockup from '@assets/image/memberReportMockup.svg'; -import {Text} from '@HDesign/index'; - -const ReportSection = () => { +const MemberReportSection = () => { return ( <div css={css({ @@ -29,4 +28,4 @@ const ReportSection = () => { ); }; -export default ReportSection; +export default MemberReportSection; diff --git a/client/src/router.tsx b/client/src/router.tsx index 735b09786..51162c775 100644 --- a/client/src/router.tsx +++ b/client/src/router.tsx @@ -4,12 +4,8 @@ import {AdminPage} from '@pages/EventPage/AdminPage'; import {HomePage} from '@pages/EventPage/HomePage'; import ErrorPage from '@pages/ErrorPage/ErrorPage'; import EventLoginPage from '@pages/EventPage/AdminPage/EventLoginPage'; -import AddBillFunnel from '@pages/AddBillFunnel/AddBillFunnel'; -import CreateEventFunnel from '@pages/CreateEventPage/CreateEventFunnel'; -import EventMember from '@pages/EventPage/AdminPage/EventMember'; -import EditBillPage from '@pages/EditBillPage/EditBillPage'; -import Account from '@pages/AccountPage/Account'; +import {CompleteCreateEventPage, SetEventNamePage, SetEventPasswordPage} from '@pages/CreateEventPage'; import {MainPage} from '@pages/MainPage'; import {EventPage} from '@pages/EventPage'; @@ -28,9 +24,16 @@ const router = createBrowserRouter([ element: <MainPage />, }, { - path: ROUTER_URLS.createEvent, - - element: <CreateEventFunnel />, + path: ROUTER_URLS.eventCreateName, + element: <SetEventNamePage />, + }, + { + path: ROUTER_URLS.eventCreatePassword, + element: <SetEventPasswordPage />, + }, + { + path: ROUTER_URLS.eventCreateComplete, + element: <CompleteCreateEventPage />, }, { path: ROUTER_URLS.event, @@ -44,22 +47,6 @@ const router = createBrowserRouter([ }, ], }, - { - path: ROUTER_URLS.addBill, - element: <AddBillFunnel />, - }, - { - path: ROUTER_URLS.member, - element: <EventMember />, - }, - { - path: ROUTER_URLS.editBill, - element: <EditBillPage />, - }, - { - path: ROUTER_URLS.eventEdit, - element: <Account />, - }, { path: '*', element: <ErrorPage />, diff --git a/client/src/store/stepListStore.ts b/client/src/store/stepListStore.ts new file mode 100644 index 000000000..07f3b107f --- /dev/null +++ b/client/src/store/stepListStore.ts @@ -0,0 +1,16 @@ +import {create} from 'zustand'; + +import {ConvertedAction} from 'types/serviceType'; + +type State = { + stepList: ConvertedAction[]; +}; + +type Action = { + updateStepList: (stepList: State['stepList']) => void; +}; + +export const useStepListStore = create<State & Action>(set => ({ + stepList: [], + updateStepList: stepList => set(() => ({stepList})), +})); diff --git a/client/src/store/stepsStore.ts b/client/src/store/stepsStore.ts deleted file mode 100644 index e89adf392..000000000 --- a/client/src/store/stepsStore.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {create} from 'zustand'; - -import {Steps} from 'types/serviceType'; - -type State = { - steps: Steps[]; -}; - -type Action = { - updateSteps: (stepList: State['steps']) => void; -}; - -export const useBillsStore = create<State & Action>(set => ({ - steps: [], - updateSteps: steps => set(() => ({steps})), -})); diff --git a/client/src/store/totalExpenseAmountStore.ts b/client/src/store/totalExpenseAmountStore.ts index cce46575e..e9ebcf52a 100644 --- a/client/src/store/totalExpenseAmountStore.ts +++ b/client/src/store/totalExpenseAmountStore.ts @@ -1,6 +1,6 @@ import {create} from 'zustand'; -import {Step as StepType} from 'types/serviceType'; +import {BillStep, MemberStep} from 'types/serviceType'; import {getTotalExpenseAmount} from '@utils/caculateExpense'; @@ -9,10 +9,10 @@ type State = { }; type Action = { - updateTotalExpenseAmount: (steps: StepType[]) => void; + updateTotalExpenseAmount: (stepList: (MemberStep | BillStep)[]) => void; }; export const useTotalExpenseAmountStore = create<State & Action>(set => ({ totalExpenseAmount: 0, - updateTotalExpenseAmount: (steps: StepType[]) => set({totalExpenseAmount: getTotalExpenseAmount(steps)}), + updateTotalExpenseAmount: stepList => set({totalExpenseAmount: getTotalExpenseAmount(stepList)}), })); diff --git a/client/src/types/fetchErrorType.ts b/client/src/types/fetchErrorType.ts new file mode 100644 index 000000000..19fe8ee6f --- /dev/null +++ b/client/src/types/fetchErrorType.ts @@ -0,0 +1,11 @@ +import {ErrorInfo} from '@components/AppErrorBoundary/ErrorCatcher'; + +import {Method} from '@apis/fetcher'; + +export type FetchErrorType = Error & { + requestBody: string; + status: number; + endpoint: string; + errorInfo: ErrorInfo; + method: Method; +}; diff --git a/client/src/types/kakao.d.ts b/client/src/types/kakao.d.ts deleted file mode 100644 index 4d72a9833..000000000 --- a/client/src/types/kakao.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -declare global { - interface Window { - Kakao: typeof Kakao; - } -} - -namespace Kakao { - function init(appKey: string): void; - function isInitialized(): boolean; - - namespace Share { - function cleanup(): void; - function sendDefault(params: sendDefaultParams): void; - - interface sendDefaultParams { - objectType: 'feed'; - content: { - title: string; - imageUrl: string; - imageWidth?: number; - imageHeight?: number; - description: string; - link: { - mobileWebUrl: string; - webUrl: string; - }; - }; - buttonTitle?: string; - buttons?: { - title: string; - link: { - webUrl: string; - mobileWebUrl: string; - }; - }[]; - } - } -} diff --git a/client/src/types/serviceType.ts b/client/src/types/serviceType.ts index a2ecca3aa..0467995f1 100644 --- a/client/src/types/serviceType.ts +++ b/client/src/types/serviceType.ts @@ -1,67 +1,80 @@ -// ******************************************************************* -// ******************** UX ๊ฐœ์„  ์ดํ›„ ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„๋“ค 24.09.19 **************** -// ******************************************************************* +export type MemberType = 'IN' | 'OUT'; -export interface Steps { - steps: Step[]; -} +export type InOutType = '๋Šฆ์ฐธ' | 'ํƒˆ์ฃผ'; -export interface Step { - bills: Bill[]; - members: Member[]; -} +export type MemberReport = { + name: string; + price: number; +}; -export interface Bill { - id: number; +export type MemberReportInAction = MemberReport & { + isFixed: boolean; +}; + +export type Bill = { title: string; price: number; +}; + +type StepBase = { + members: string[]; +}; + +export type MemberStep = StepBase & { + type: MemberType; + stepName: null; + actions: MemberAction[]; +}; + +export type BillStep = StepBase & { + type: 'BILL'; + stepName: string; + actions: BillAction[]; +}; + +// (@weadie) ์ค€ ๋ฐ์ดํ„ฐ ํ˜•์‹์—์„œ steps๋ฅผ ๋นผ๋‚ด flatํ•˜๊ฒŒ ์‚ฌ์šฉ์ค‘. ์ผ๊ด€์„ฑ์žˆ๊ฒŒ ํ•˜๋Š”๊ฒŒ ์ข‹๊ธด ํ•˜๋‚˜ ์‚ฌ์šฉ์‹œ ๋ฒˆ๊ฑฐ๋กœ์›€์ด ์žˆ์„ ๊ฑฐ๋ผ๊ณ  ํŒ๋‹จ. +export type StepList = { + steps: (MemberStep | BillStep)[]; +}; + +export type Action = { + actionId: number; + name: string; + price: number | null; + sequence: number; isFixed: boolean; -} +}; -export interface BillDetail { - id: number; - memberName: string; +export type BillAction = Omit<Action, 'price'> & { price: number; - isFixed: boolean; -} +}; -export interface BillDetails { - members: BillDetail[]; -} +export type MemberAction = Omit<Action, 'price'> & { + price: null; +}; -export interface Member { - id: number; +export type Member = { name: string; -} - -export interface Members { - members: Member[]; -} - -export interface MemberWithDeposited extends Member { - isDeposited: boolean; -} - -export interface AllMembers { - members: MemberWithDeposited[]; -} -export interface EventId { - eventId: string; -} - -export interface Event { - eventName: string; - bankName: string; - accountNumber: string; -} - -export interface Report { - memberId: number; - memberName: string; - isDeposited: boolean; - price: number; -} + status: MemberType; +}; + +export type ActionType = 'IN' | 'OUT' | 'BILL'; + +// export type StepList = { +// actions: Action[]; +// }; + +export type ConvertedAction = { + actionId: number; + name: string; + price: string | null; + sequence: number; + type: ActionType; +}; + +export type InputPair = Omit<Bill, 'price'> & { + price: string; + index: number; +}; -export interface Reports { - reports: Report[]; -} +export type BillInputType = 'title' | 'price'; diff --git a/client/src/types/toastType.ts b/client/src/types/toastType.ts deleted file mode 100644 index d81a20572..000000000 --- a/client/src/types/toastType.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {Theme} from '@components/Design/theme/theme.type'; - -export type ToastPosition = 'bottom' | 'top'; - -export type ToastOptions = { - showingTime?: number; - isAutoClosed?: boolean; - isCloseOnClick?: boolean; - position?: ToastPosition; - bottom?: string; - top?: string; - theme?: Theme; -}; - -export type ToastMessage = string; - -export type ToastArgs = { - message: ToastMessage; - options: ToastOptions; -}; diff --git a/client/src/utils/NetworkStateCatcher.tsx b/client/src/utils/NetworkStateCatcher.tsx deleted file mode 100644 index 1a8158ec8..000000000 --- a/client/src/utils/NetworkStateCatcher.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import {useEffect} from 'react'; - -import {useToast} from '@hooks/useToast/useToast'; -import toast from '@hooks/useToast/toast'; - -const NetworkStateCatcher = () => { - const handleNetworkOnline = () => { - // closeToast(); - }; - - const handleNetworkOffline = () => { - // TODO: (@weadie) ํ† ์ŠคํŠธ ๋†’์ด๋Š” z-index ์ด์Šˆ๊ฐ€ ํ•ด๊ฒฐ๋˜๋ฉด ๋ฐ˜์˜ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. - toast.error('๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”.', { - isAutoClosed: false, - position: 'bottom', - bottom: '6rem', - }); - }; - - const addNetworkStateEventListener = () => { - window.addEventListener('online', handleNetworkOnline); - window.addEventListener('offline', handleNetworkOffline); - }; - - const removeNetworkStateEventListener = () => { - window.removeEventListener('online', handleNetworkOnline); - window.removeEventListener('offline', handleNetworkOffline); - }; - - useEffect(() => { - addNetworkStateEventListener(); - - return removeNetworkStateEventListener; - }, []); - - return null; -}; - -export default NetworkStateCatcher; diff --git a/client/src/utils/caculateExpense.ts b/client/src/utils/caculateExpense.ts index 2ee8c2fa5..8b41af8c3 100644 --- a/client/src/utils/caculateExpense.ts +++ b/client/src/utils/caculateExpense.ts @@ -1,8 +1,14 @@ -import {Step} from 'types/serviceType'; +import {BillAction, BillStep, MemberStep} from 'types/serviceType'; -export const getTotalExpenseAmount = (steps: Step[]) => { - return steps.reduce((total, step) => { - const stepTotal = step.bills.reduce((sum, bill) => sum + bill.price, 0); - return total + stepTotal; +export const calculateStepExpense = (actions: BillAction[]) => { + return actions.reduce((sum, {price}) => sum + price, 0); +}; + +export const getTotalExpenseAmount = (stepList: (MemberStep | BillStep)[]) => { + return stepList.reduce((sum, {type, actions}) => { + if (type === 'BILL') { + return sum + calculateStepExpense(actions); + } + return sum; }, 0); }; diff --git a/client/src/utils/captureError.ts b/client/src/utils/captureError.ts index 2c445cf82..67a30ac99 100644 --- a/client/src/utils/captureError.ts +++ b/client/src/utils/captureError.ts @@ -1,53 +1,49 @@ -import RequestError from '@errors/RequestError'; +import {ErrorInfo} from '@components/AppErrorBoundary/ErrorCatcher'; import sendLogToSentry from './sendLogToSentry'; -export const captureError = async (error: Error) => { +export const captureError = async (error: Error, errorInfo: ErrorInfo) => { // prod ํ™˜๊ฒฝ์—์„œ๋งŒ Sentry capture ์‹คํ–‰ if (process.env.NODE_ENV !== 'production') return; - if (error instanceof RequestError) { - switch (error.errorCode) { - case 'INTERNAL_SERVER_ERROR': - sendLogToSentry({error, level: 'fatal'}); - break; + switch (errorInfo?.errorCode) { + case 'INTERNAL_SERVER_ERROR': + sendLogToSentry({error, errorInfo, level: 'fatal'}); + break; - case 'FORBIDDEN': - sendLogToSentry({error}); + case 'FORBIDDEN': + sendLogToSentry({error, errorInfo}); - break; + break; - case 'TOKEN_INVALID': - sendLogToSentry({error}); + case 'TOKEN_INVALID': + sendLogToSentry({error, errorInfo}); - break; + break; - case 'TOKEN_EXPIRED': - sendLogToSentry({error}); + case 'TOKEN_EXPIRED': + sendLogToSentry({error, errorInfo}); - break; + break; - case 'TOKEN_NOT_FOUND': - sendLogToSentry({error}); + case 'TOKEN_NOT_FOUND': + sendLogToSentry({error, errorInfo}); - break; + break; - // ๋น„๋ฐ€ ๋ฒˆํ˜ธ๋ฅผ ๊นŒ๋จน๋Š” ์‚ฌ๋žŒ์ด ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์ง€ ์ถ”์ธกํ•˜๊ธฐ ์œ„ํ•จ - case 'PASSWORD_INVALID': - sendLogToSentry({error, level: 'debug'}); + // ๋น„๋ฐ€ ๋ฒˆํ˜ธ๋ฅผ ๊นŒ๋จน๋Š” ์‚ฌ๋žŒ์ด ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์ง€ ์ถ”์ธกํ•˜๊ธฐ ์œ„ํ•จ + case 'PASSWORD_INVALID': + sendLogToSentry({error, errorInfo, level: 'debug'}); - break; + break; - // 1์ฒœ๋งŒ์› ์ด์ƒ ์ž…๋ ฅํ•˜๋Š” ์‚ฌ๋žŒ์ด ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์ง€ ์ถ”์ธกํ•˜๊ธฐ ์œ„ํ•จ - case 'BILL_ACTION_PRICE_INVALID': - sendLogToSentry({error, level: 'debug'}); - break; + // 1์ฒœ๋งŒ์› ์ด์ƒ ์ž…๋ ฅํ•˜๋Š” ์‚ฌ๋žŒ์ด ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์ง€ ์ถ”์ธกํ•˜๊ธฐ ์œ„ํ•จ + case 'BILL_ACTION_PRICE_INVALID': + sendLogToSentry({error, errorInfo, level: 'debug'}); + break; - default: - sendLogToSentry({error, level: 'fatal'}); - break; - } - } else { - sendLogToSentry({error, level: 'fatal'}); + default: + sendLogToSentry({error, errorInfo, level: 'fatal'}); + break; } }; diff --git a/client/src/utils/detectDevice.ts b/client/src/utils/detectDevice.ts deleted file mode 100644 index 2b1df2ea9..000000000 --- a/client/src/utils/detectDevice.ts +++ /dev/null @@ -1,20 +0,0 @@ -export const isMobileDevice = () => { - const userAgent = window.navigator.userAgent; - const mobileRegex = [/Android/i, /iPhone/i, /iPad/i, /iPod/i, /BlackBerry/i, /Windows Phone/i]; - - return mobileRegex.some(mobile => userAgent.match(mobile)); -}; - -export const isIOS = () => { - const userAgent = window.navigator.userAgent; - const iosRegex = [/iPhone/i, /iPad/i, /iPod/i]; - - return iosRegex.some(device => userAgent.match(device)); -}; - -export const isAndroid = () => { - const userAgent = window.navigator.userAgent; - const androidRegex = [/Android/i, /BlackBerry/i, /Windows Phone/i]; - - return androidRegex.some(device => userAgent.match(device)); -}; diff --git a/client/src/utils/getDeletedLastPath.ts b/client/src/utils/getDeletedLastPath.ts deleted file mode 100644 index f2edfb154..000000000 --- a/client/src/utils/getDeletedLastPath.ts +++ /dev/null @@ -1,7 +0,0 @@ -const getDeletedLastPath = (url: string) => { - const urlParts = url.split('/'); - urlParts.pop(); - return urlParts.join('/'); -}; - -export default getDeletedLastPath; diff --git a/client/src/utils/groupActions.ts b/client/src/utils/groupActions.ts new file mode 100644 index 000000000..a6347167d --- /dev/null +++ b/client/src/utils/groupActions.ts @@ -0,0 +1,27 @@ +import {BillStep, ConvertedAction, MemberStep} from 'types/serviceType'; + +import stepListToAction from './stepListToActions'; + +const groupActions = (stepList: (BillStep | MemberStep)[]) => { + const actions = stepListToAction(stepList); + const groupedActions: ConvertedAction[][] = []; + + let group: ConvertedAction[] = []; + + actions.forEach((action, index) => { + if (group.length === 0 || group[group.length - 1].type === action.type) { + group.push(action); + } else { + groupedActions.push(group); + group = []; + } + + if (index === actions.length - 1) { + groupedActions.push(group); + } + }); + + return groupedActions; +}; + +export default groupActions; diff --git a/client/src/utils/isRequestError.ts b/client/src/utils/isRequestError.ts deleted file mode 100644 index 98dfc90f5..000000000 --- a/client/src/utils/isRequestError.ts +++ /dev/null @@ -1,7 +0,0 @@ -import RequestError from '@errors/RequestError'; - -const isRequestError = (error: Error) => { - return error instanceof RequestError; -}; - -export default isRequestError; diff --git a/client/src/utils/sendLogToSentry.ts b/client/src/utils/sendLogToSentry.ts index e7aec9286..22d736b6c 100644 --- a/client/src/utils/sendLogToSentry.ts +++ b/client/src/utils/sendLogToSentry.ts @@ -1,6 +1,10 @@ import * as Sentry from '@sentry/react'; -import RequestError from '../errors/RequestError'; +import {ErrorInfo} from '@components/AppErrorBoundary/ErrorCatcher'; + +import {UNKNOWN_ERROR} from '@constants/errorMessage'; + +import FetchError from '../errors/FetchError'; /** * level์€ ์•„๋ž˜์™€ ๊ฐ™์€ ์šฉ๋„์— ๋งž๊ฒŒ ์ง€์ •ํ•ด์ค๋‹ˆ๋‹ค. @@ -17,34 +21,44 @@ type SentryLevel = 'fatal' | 'error' | 'warning' | 'info' | 'debug' | 'log'; type SendLogToSentry = { level?: SentryLevel; error: Error; + errorInfo: ErrorInfo; }; -const sendLogToSentry = ({level = 'error', error}: SendLogToSentry) => { +const sendLogToSentry = ({level = 'error', error, errorInfo}: SendLogToSentry) => { Sentry.withScope(scope => { + const {errorCode, message} = errorInfo; scope.setLevel(level); + scope.setTag('environment', process.env.NODE_ENV); - if (error instanceof RequestError) { - const {errorCode, message} = error; + + if (error instanceof FetchError) { scope.setTags({ endpoint: error.endpoint, url: window.location.href, + errorCode, errorMessage: message, status: error.status, - errorCode, - requestBody: JSON.stringify(error.requestBody), + // requestBody: JSON.stringify(error.requestBody), method: error.method, }); - Sentry.captureMessage(`${errorCode}`); - } else { - const {name, message} = error; + Sentry.captureMessage(`${errorCode}`); + } else if (error instanceof Error) { scope.setTags({ url: window.location.href, - name, - message, + errorCode, + errorMessage: message, }); - Sentry.captureMessage(`${name}`); + Sentry.captureMessage(`${errorCode}`); + } else { + scope.setTags({ + url: window.location.href, + errorCode, + message: UNKNOWN_ERROR, + name: UNKNOWN_ERROR, + }); + Sentry.captureMessage(`${errorCode}`); } }); }; diff --git a/client/src/utils/stepListToActions.ts b/client/src/utils/stepListToActions.ts new file mode 100644 index 000000000..5fe1bb3a7 --- /dev/null +++ b/client/src/utils/stepListToActions.ts @@ -0,0 +1,23 @@ +import {BillStep, ConvertedAction, MemberStep} from 'types/serviceType'; + +const stepListToAction = (stepList: (BillStep | MemberStep)[]) => { + // (@todari) test์šฉ์ด๋ผ ์ž„์‹œ๋กœ any ์‚ฌ์šฉํ• ๊ฒŒ์šฉ... + // Action์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•˜๋Š”๋ฐ serviceType์˜ ๊ธฐ์กด Action์ด๋ž‘ ๊ฒน์ณ์„œ์š”~~~ + const actions: ConvertedAction[] = []; + + stepList.forEach(step => { + step.actions.forEach(action => { + actions.push({ + actionId: action.actionId, + name: action.name, + price: action.price ? action.price.toLocaleString() : null, + sequence: action.sequence, + type: step.type, + }); + }); + }); + + return actions; +}; + +export default stepListToAction; diff --git a/client/src/utils/validate/validateAccountNumber.ts b/client/src/utils/validate/validateAccountNumber.ts deleted file mode 100644 index fb100a22b..000000000 --- a/client/src/utils/validate/validateAccountNumber.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {ERROR_MESSAGE} from '@constants/errorMessage'; -import REGEXP from '@constants/regExp'; -import RULE from '@constants/rule'; - -import {ValidateResult} from './type'; - -const validateAccountNumber = (accountNumber: string): ValidateResult => { - const isValidateType = () => { - return REGEXP.accountNumber.test(accountNumber); - }; - - const isValidateLength = () => { - return accountNumber.length >= RULE.minAccountNumberLength && accountNumber.length <= RULE.maxAccountNumberLength; - }; - - if (isValidateType() && isValidateLength()) { - return {isValid: true, errorMessage: null}; - } - - return {isValid: false, errorMessage: ERROR_MESSAGE.invalidAccountNumber}; -}; - -export default validateAccountNumber; diff --git a/client/src/utils/validate/validateEventName.ts b/client/src/utils/validate/validateEventName.ts index 1c88fd4b3..93f4ecef1 100644 --- a/client/src/utils/validate/validateEventName.ts +++ b/client/src/utils/validate/validateEventName.ts @@ -7,7 +7,6 @@ const validateEventName = (name: string): ValidateResult => { if (name.length > RULE.maxEventNameLength) { return {isValid: false, errorMessage: ERROR_MESSAGE.eventName}; } - return {isValid: true, errorMessage: null}; }; diff --git a/client/src/utils/validate/validateMemberName.ts b/client/src/utils/validate/validateMemberName.ts index b23ca74f2..bb87122a2 100644 --- a/client/src/utils/validate/validateMemberName.ts +++ b/client/src/utils/validate/validateMemberName.ts @@ -16,7 +16,15 @@ const validateMemberName = (name: string): ValidateResult => { return true; }; - if (validateOnlyString() && validateLength()) { + const validateEmpty = () => { + if (!name.trim().length) { + errorMessage = ERROR_MESSAGE.preventEmpty; + return false; + } + return true; + }; + + if (validateOnlyString() && validateLength() && validateEmpty()) { return {isValid: true, errorMessage: null}; } diff --git a/client/src/utils/validate/validateBillDetails.ts b/client/src/utils/validate/validateMemberReportInAction.ts similarity index 85% rename from client/src/utils/validate/validateBillDetails.ts rename to client/src/utils/validate/validateMemberReportInAction.ts index a77a154a5..b4e6c2a9a 100644 --- a/client/src/utils/validate/validateBillDetails.ts +++ b/client/src/utils/validate/validateMemberReportInAction.ts @@ -3,7 +3,7 @@ import RULE from '@constants/rule'; import {ValidateResult} from './type'; -const validateBillDetails = (price: string, totalPrice: number): ValidateResult => { +const validateMemberReportInAction = (price: string, totalPrice: number): ValidateResult => { let errorMessage = null; const numberTypePrice = Number(price); @@ -30,4 +30,4 @@ const validateBillDetails = (price: string, totalPrice: number): ValidateResult return {isValid: false, errorMessage: errorMessage || ERROR_MESSAGE.invalidInput}; }; -export default validateBillDetails; +export default validateMemberReportInAction; diff --git a/client/src/utils/validate/validatePurchase.ts b/client/src/utils/validate/validatePurchase.ts new file mode 100644 index 000000000..9915ce8b7 --- /dev/null +++ b/client/src/utils/validate/validatePurchase.ts @@ -0,0 +1,47 @@ +import type {Bill} from 'types/serviceType'; + +import {ERROR_MESSAGE} from '@constants/errorMessage'; +import RULE from '@constants/rule'; +import REGEXP from '@constants/regExp'; + +import {ValidateResult} from './type'; + +const validatePurchase = (inputPair: Bill): ValidateResult => { + const {title, price} = inputPair; + let errorMessage: string | null = null; + + const errorInfo = { + price: false, + title: false, + }; + + const validatePrice = () => { + if (price > RULE.maxPrice) { + errorMessage = ERROR_MESSAGE.purchasePrice; + errorInfo.price = true; + return false; + } + + errorInfo.price = false; + return true; + }; + + const validateTitle = () => { + if (!REGEXP.purchaseTitle.test(title)) { + errorMessage = ERROR_MESSAGE.purchaseTitle; + errorInfo.title = true; + return false; + } + + errorInfo.title = false; + return true; + }; + + if (validatePrice() && validateTitle()) { + return {isValid: true, errorMessage: null}; + } + + return {isValid: false, errorMessage, errorInfo}; +}; + +export default validatePurchase; diff --git a/client/tsconfig.json b/client/tsconfig.json index f68912ec3..84c7c054a 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -44,15 +44,7 @@ "@mocks/*": ["mocks/*"], "@pages/*": ["pages/*"], "@utils/*": ["utils/*"], - "@errors/*": ["errors/*"], - - "@HDesign/*": ["components/Design/*"], - "@HDcomponents/*": ["components/Design/components/*"], - "@token/*": ["components/Design/token/*"], - "@layouts/*": ["components/Design/layouts/*"], - "@type/*": ["components/Design/type/*"], - "@theme/*": ["components/Design/theme/*"], - "@HDutils/*": ["components/Design/utils/*"] + "@errors/*": ["errors/*"] }, "outDir": "./dist" }, diff --git a/client/webpack.common.mjs b/client/webpack.common.mjs index 90879f2f9..160baf0ca 100644 --- a/client/webpack.common.mjs +++ b/client/webpack.common.mjs @@ -22,13 +22,6 @@ export default { '@pages': path.resolve(__dirname, 'src/pages/'), '@utils': path.resolve(__dirname, 'src/utils/'), '@errors': path.resolve(__dirname, 'src/errors/'), - '@HDesign': path.resolve(__dirname, 'src/components/Design/'), - '@HDcomponents': path.resolve(__dirname, 'src/components/Design/components/'), - '@HDutils': path.resolve(__dirname, 'src/components/Design/utils/'), - '@token': path.resolve(__dirname, 'src/components/Design/token/'), - '@theme': path.resolve(__dirname, 'src/components/Design/theme/'), - '@layouts': path.resolve(__dirname, 'src/components/Design/layouts/'), - '@type': path.resolve(__dirname, 'src/components/Design/type/'), }, }, module: { @@ -46,10 +39,6 @@ export default { }, ], }, - { - test: /\.png$/i, - loader: 'file-loader', - }, ], }, plugins: [ diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 000000000..671ee930b --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,244 @@ +# Created by https://www.toptal.com/developers/gitignore/api/java,intellij,gradle,macos,windows,linux +# Edit at https://www.toptal.com/developers/gitignore?templates=java,intellij,gradle,macos,windows,linux + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Gradle ### +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties + +# Cache of project +.gradletasknamecache + +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +### Gradle Patch ### +# Java heap dump +*.hprof + +# End of https://www.toptal.com/developers/gitignore/api/java,intellij,gradle,macos,windows,linux diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 000000000..df2cf44e0 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,9 @@ +FROM openjdk:17-jdk-slim + +WORKDIR /app + +COPY /build/libs/*.jar /app/haengdong-0.0.1-SNAPSHOT.jar + +EXPOSE 8080 +ENTRYPOINT ["java"] +CMD ["-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE}", "-Duser.timezone=Asia/Seoul", "-jar", "haengdong-0.0.1-SNAPSHOT.jar"] diff --git a/server/build.gradle b/server/build.gradle new file mode 100644 index 000000000..4229de130 --- /dev/null +++ b/server/build.gradle @@ -0,0 +1,86 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.3.1' + id 'io.spring.dependency-management' version '1.1.5' + id 'org.asciidoctor.jvm.convert' version '3.3.2' +} + +group = 'server' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } + asciidoctorExt +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-actuator' + + implementation 'io.jsonwebtoken:jjwt:0.9.1' + implementation 'javax.xml.bind:jaxb-api:2.3.1' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + runtimeOnly 'com.h2database:h2' + runtimeOnly 'com.mysql:mysql-connector-j' + + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' + testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' +} + +ext { + snippetsDir = file('build/generated-snippets') +} + +test { + useJUnitPlatform() + outputs.dir snippetsDir +} + +asciidoctor { + inputs.dir snippetsDir + configurations 'asciidoctorExt' + baseDirFollowsSourceFile() + dependsOn test +} + +tasks.resolveMainClassName { + dependsOn 'copyApiDocuments' +} + +tasks.register('copyApiDocuments', Copy) { + dependsOn asciidoctor + from file("build/docs/asciidoc") + into file("build/resources/main/static/docs") +} + +bootJar { + dependsOn copyApiDocuments +} + +jar { + enabled = false +} + +build { + dependsOn copyApiDocuments +} diff --git a/server/docs/24-08-04-erd.sql b/server/docs/24-08-04-erd.sql new file mode 100644 index 000000000..ae2fbc4a5 --- /dev/null +++ b/server/docs/24-08-04-erd.sql @@ -0,0 +1,65 @@ +-- Create tables +CREATE TABLE action +( + event_id BIGINT, + id BIGINT AUTO_INCREMENT, + sequence BIGINT, + PRIMARY KEY (id) +); + +CREATE TABLE bill_action +( + action_id BIGINT UNIQUE, + id BIGINT AUTO_INCREMENT, + price BIGINT, + title VARCHAR(30), + PRIMARY KEY (id) +); + +CREATE TABLE event +( + id BIGINT AUTO_INCREMENT, + name VARCHAR(255), + token VARCHAR(255), + PRIMARY KEY (id) +); + +CREATE TABLE event_step +( + event_id BIGINT, + id BIGINT AUTO_INCREMENT, + sequence BIGINT, + name VARCHAR(255), + PRIMARY KEY (id) +); + +CREATE TABLE member_action +( + action_id BIGINT UNIQUE, + id BIGINT AUTO_INCREMENT, + member_group_id BIGINT, + member_name VARCHAR(255), + status ENUM('IN', 'OUT'), + PRIMARY KEY (id) +); + +-- Add foreign key constraints +ALTER TABLE action + ADD CONSTRAINT FKgf0qmub9va1xbe44nehny31yw + FOREIGN KEY (event_id) + REFERENCES event (id); + +ALTER TABLE bill_action + ADD CONSTRAINT FK54tx517tp0ry6453olkply4us + FOREIGN KEY (action_id) + REFERENCES action (id); + +ALTER TABLE event_step + ADD CONSTRAINT FKe3rkib91cvl0x5w9wqkshmn81 + FOREIGN KEY (event_id) + REFERENCES event (id); + +ALTER TABLE member_action + ADD CONSTRAINT FK5jna51dn8fs2ir52l4uwn517u + FOREIGN KEY (action_id) + REFERENCES action (id); diff --git a/server/docs/24-08-04-erd.svg b/server/docs/24-08-04-erd.svg new file mode 100644 index 000000000..5a4bac225 --- /dev/null +++ b/server/docs/24-08-04-erd.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than draw.io --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1993px" height="1581px" viewBox="-0.5 -0.5 1993 1581" content="<mxfile host="app.diagrams.net" modified="2024-07-25T04:17:06.208Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" etag="gR5VLfYLO6MRu5dHcV28" version="24.7.3" type="github"> <diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1"> <mxGraphModel dx="2380" dy="2150" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <root> <mxCell id="WIyWlLk6GJQsqaUBKTNV-0" /> <mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0" /> <mxCell id="8gZzuRhjrYuwNxX9kY4q-98" value="" style="rounded=0;whiteSpace=wrap;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="-442" y="-590" width="1992" height="1580" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-47" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=ERone;startFill=0;endArrow=ERzeroToMany;endFill=0;dashed=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-0" target="8gZzuRhjrYuwNxX9kY4q-37" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-66" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=ERone;startFill=0;endArrow=ERzeroToMany;endFill=0;dashed=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-0" target="8gZzuRhjrYuwNxX9kY4q-56" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-0" value="Event" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="40" y="40" width="280" height="120" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-1" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-2" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-3" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-137" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-7" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-8" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-9" value="token" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-138" value="varchar(20)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-4" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-5" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-6" value="name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-139" value="varchar(255)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-37" value="Event_Step" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="40" y="240" width="280" height="150" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-38" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-39" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-40" value="event_step_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-143" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-41" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-42" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-43" value="name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-144" value="varchar(30)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-44" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-45" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-46" value="sequence" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-145" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-48" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-49" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-50" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-146" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-77" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;startArrow=ERone;startFill=0;endArrow=ERone;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-56" target="8gZzuRhjrYuwNxX9kY4q-67" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-91" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;startArrow=ERone;startFill=0;endArrow=ERone;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-56" target="8gZzuRhjrYuwNxX9kY4q-81" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-56" value="Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="414" y="40" width="280" height="120" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-57" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-58" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-59" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-140" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-60" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-61" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-62" value="sequence" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-141" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-63" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-64" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-65" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-142" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-67" value="Bill_Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="414" y="240" width="280" height="150" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-68" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-69" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-70" value="bill_action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-147" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-71" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-72" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-73" value="title" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-148" value="varchar(30)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-78" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-79" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-80" value="price" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-149" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-74" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-75" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-76" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-150" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-81" value="Member_Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="790" y="40" width="280" height="180" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-82" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-83" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-84" value="member_action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-151" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-85" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-86" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-87" value="member_name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-152" value="varchar(20)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-92" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-93" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-94" value="status" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-153" value="varchar(10)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-95" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-96" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-97" value="member_group_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-154" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-88" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="150" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-89" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-90" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-155" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> " resource="https://app.diagrams.net/?src=about#Hkunsanglee%2Fcafekiosk-study%2Fmain%2Fsrc%2Fmain%2Fresources%2Fexample2.svg#%7B%22pageId%22%3A%22C5RBs43oDa-KdzZeNtuy%22%7D"><defs/><g><g data-cell-id="WIyWlLk6GJQsqaUBKTNV-0"><g data-cell-id="WIyWlLk6GJQsqaUBKTNV-1"><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-98"><g><rect x="0" y="0" width="1992" height="1580" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-47"><g><path d="M 622 750 L 622 814.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 626 754 L 618 754" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="622" cy="818" rx="3" ry="3" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 626 830 L 622 822 L 618 830 M 622 822 L 622 830" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-66"><g><path d="M 762 690 L 840.5 690" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 766 686 L 766 694" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="844" cy="690" rx="3" ry="3" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 856 686 L 848 690 L 856 694 M 848 690 L 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-0"><g><path d="M 482 660 L 482 630 L 762 630 L 762 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 482 660 L 482 750 L 762 750 L 762 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 482 660 L 762 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 512 660 L 512 690 L 512 720 L 512 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 632 660 L 632 690 L 632 720 L 632 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 622px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Event</div></div></div></foreignObject><text x="622" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Event</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-1"><g><path d="M 482 660 M 762 660 M 762 690 L 482 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-2"><g><rect x="482" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 660 M 512 660 M 512 690 M 482 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="497" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-3"><g><rect x="512" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 660 M 632 660 M 632 690 M 512 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="520" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-137"><g><rect x="632" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 660 M 762 660 M 762 690 M 632 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-7"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-8"><g><rect x="482" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 690 M 512 690 M 512 720 M 482 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-9"><g><rect x="512" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 690 M 632 690 M 632 720 M 512 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">token</div></div></div></foreignObject><text x="520" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">token</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-138"><g><rect x="632" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 690 M 762 690 M 762 720 M 632 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(20)</div></div></div></foreignObject><text x="640" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(20)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-4"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-5"><g><rect x="482" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 720 M 512 720 M 512 750 M 482 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-6"><g><rect x="512" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 720 M 632 720 M 632 750 M 512 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">name</div></div></div></foreignObject><text x="520" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-139"><g><rect x="632" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 720 M 762 720 M 762 750 M 632 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(255)</div></div></div></foreignObject><text x="640" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(255)</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-37"><g><path d="M 482 860 L 482 830 L 762 830 L 762 860" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 482 860 L 482 980 L 762 980 L 762 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 482 860 L 762 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 512 860 L 512 890 L 512 920 L 512 950 L 512 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 632 860 L 632 890 L 632 920 L 632 950 L 632 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 845px; margin-left: 622px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Event_Step</div></div></div></foreignObject><text x="622" y="849" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Event_Step</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-38"><g><path d="M 482 860 M 762 860 M 762 890 L 482 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-39"><g><rect x="482" y="860" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 860 M 512 860 M 512 890 M 482 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 875px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="497" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-40"><g><rect x="512" y="860" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 860 M 632 860 M 632 890 M 512 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 875px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">event_step_id</div></div></div></foreignObject><text x="520" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">event_step_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-143"><g><rect x="632" y="860" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 860 M 762 860 M 762 890 M 632 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 875px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-41"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-42"><g><rect x="482" y="890" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 890 M 512 890 M 512 920 M 482 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-43"><g><rect x="512" y="890" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 890 M 632 890 M 632 920 M 512 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 905px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">name</div></div></div></foreignObject><text x="520" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-144"><g><rect x="632" y="890" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 890 M 762 890 M 762 920 M 632 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 905px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(30)</div></div></div></foreignObject><text x="640" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(30)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-44"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-45"><g><rect x="482" y="920" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 920 M 512 920 M 512 950 M 482 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-46"><g><rect x="512" y="920" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 920 M 632 920 M 632 950 M 512 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 935px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">sequence</div></div></div></foreignObject><text x="520" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">sequence</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-145"><g><rect x="632" y="920" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 920 M 762 920 M 762 950 M 632 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 935px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-48"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-49"><g><rect x="482" y="950" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 950 M 512 950 M 512 980 M 482 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 965px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="497" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-50"><g><rect x="512" y="950" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 950 M 632 950 M 632 980 M 512 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 965px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="520" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-146"><g><rect x="632" y="950" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 950 M 762 950 M 762 980 M 632 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 965px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-77"><g><path d="M 996 750 L 996 830" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 1000 754 L 992 754" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 992 826 L 1000 826" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-91"><g><path d="M 1136 690 L 1184 690 L 1184 720 L 1232 720" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 1140 686 L 1140 694" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1228 724 L 1228 716" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-56"><g><path d="M 856 660 L 856 630 L 1136 630 L 1136 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 856 660 L 856 750 L 1136 750 L 1136 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 856 660 L 1136 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 886 660 L 886 690 L 886 720 L 886 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1006 660 L 1006 690 L 1006 720 L 1006 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 996px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Action</div></div></div></foreignObject><text x="996" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-57"><g><path d="M 856 660 M 1136 660 M 1136 690 L 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-58"><g><rect x="856" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 660 M 886 660 M 886 690 M 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="871" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-59"><g><rect x="886" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 660 M 1006 660 M 1006 690 M 886 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="894" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-140"><g><rect x="1006" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 660 M 1136 660 M 1136 690 M 1006 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-60"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-61"><g><rect x="856" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 690 M 886 690 M 886 720 M 856 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-62"><g><rect x="886" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 690 M 1006 690 M 1006 720 M 886 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">sequence</div></div></div></foreignObject><text x="894" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">sequence</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-141"><g><rect x="1006" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 690 M 1136 690 M 1136 720 M 1006 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-63"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-64"><g><rect x="856" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 720 M 886 720 M 886 750 M 856 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 735px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="871" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-65"><g><rect x="886" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 720 M 1006 720 M 1006 750 M 886 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="894" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-142"><g><rect x="1006" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 720 M 1136 720 M 1136 750 M 1006 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-67"><g><path d="M 856 860 L 856 830 L 1136 830 L 1136 860" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 856 860 L 856 980 L 1136 980 L 1136 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 856 860 L 1136 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 886 860 L 886 890 L 886 920 L 886 950 L 886 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1006 860 L 1006 890 L 1006 920 L 1006 950 L 1006 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 845px; margin-left: 996px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Bill_Action</div></div></div></foreignObject><text x="996" y="849" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Bill_Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-68"><g><path d="M 856 860 M 1136 860 M 1136 890 L 856 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-69"><g><rect x="856" y="860" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 860 M 886 860 M 886 890 M 856 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 875px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="871" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-70"><g><rect x="886" y="860" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 860 M 1006 860 M 1006 890 M 886 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 875px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bill_action_id</div></div></div></foreignObject><text x="894" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bill_action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-147"><g><rect x="1006" y="860" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 860 M 1136 860 M 1136 890 M 1006 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 875px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-71"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-72"><g><rect x="856" y="890" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 890 M 886 890 M 886 920 M 856 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-73"><g><rect x="886" y="890" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 890 M 1006 890 M 1006 920 M 886 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 905px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">title</div></div></div></foreignObject><text x="894" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">title</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-148"><g><rect x="1006" y="890" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 890 M 1136 890 M 1136 920 M 1006 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 905px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(30)</div></div></div></foreignObject><text x="1014" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(30)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-78"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-79"><g><rect x="856" y="920" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 920 M 886 920 M 886 950 M 856 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-80"><g><rect x="886" y="920" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 920 M 1006 920 M 1006 950 M 886 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 935px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">price</div></div></div></foreignObject><text x="894" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">price</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-149"><g><rect x="1006" y="920" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 920 M 1136 920 M 1136 950 M 1006 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 935px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-74"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-75"><g><rect x="856" y="950" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 950 M 886 950 M 886 980 M 856 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 965px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="871" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-76"><g><rect x="886" y="950" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 950 M 1006 950 M 1006 980 M 886 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 965px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="894" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-150"><g><rect x="1006" y="950" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 950 M 1136 950 M 1136 980 M 1006 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 965px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-81"><g><path d="M 1232 660 L 1232 630 L 1512 630 L 1512 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1232 660 L 1232 810 L 1512 810 L 1512 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1232 660 L 1512 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1262 660 L 1262 690 L 1262 720 L 1262 750 L 1262 780 L 1262 810" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1382 660 L 1382 690 L 1382 720 L 1382 750 L 1382 780 L 1382 810" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 1372px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Member_Action</div></div></div></foreignObject><text x="1372" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Member_Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-82"><g><path d="M 1232 660 M 1512 660 M 1512 690 L 1232 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-83"><g><rect x="1232" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 660 M 1262 660 M 1262 690 M 1232 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 1233px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="1247" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-84"><g><rect x="1262" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 660 M 1382 660 M 1382 690 M 1262 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">member_action_id</div></div></div></foreignObject><text x="1270" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">member_action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-151"><g><rect x="1382" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 660 M 1512 660 M 1512 690 M 1382 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-85"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-86"><g><rect x="1232" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 690 M 1262 690 M 1262 720 M 1232 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-87"><g><rect x="1262" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 690 M 1382 690 M 1382 720 M 1262 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">member_name</div></div></div></foreignObject><text x="1270" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">member_name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-152"><g><rect x="1382" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 690 M 1512 690 M 1512 720 M 1382 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(20)</div></div></div></foreignObject><text x="1390" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(20)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-92"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-93"><g><rect x="1232" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 720 M 1262 720 M 1262 750 M 1232 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-94"><g><rect x="1262" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 720 M 1382 720 M 1382 750 M 1262 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">status</div></div></div></foreignObject><text x="1270" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">status</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-153"><g><rect x="1382" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 720 M 1512 720 M 1512 750 M 1382 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(10)</div></div></div></foreignObject><text x="1390" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(10)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-95"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-96"><g><rect x="1232" y="750" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 750 M 1262 750 M 1262 780 M 1232 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-97"><g><rect x="1262" y="750" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 750 M 1382 750 M 1382 780 M 1262 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 765px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">member_group_id</div></div></div></foreignObject><text x="1270" y="769" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">member_group_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-154"><g><rect x="1382" y="750" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 750 M 1512 750 M 1512 780 M 1382 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 765px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="769" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-88"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-89"><g><rect x="1232" y="780" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 780 M 1262 780 M 1262 810 M 1232 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 795px; margin-left: 1233px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="1247" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-90"><g><rect x="1262" y="780" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 780 M 1382 780 M 1382 810 M 1262 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 795px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="1270" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-155"><g><rect x="1382" y="780" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 780 M 1512 780 M 1512 810 M 1382 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 795px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g></g></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file diff --git a/server/gradle/wrapper/gradle-wrapper.jar b/server/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..e6441136f Binary files /dev/null and b/server/gradle/wrapper/gradle-wrapper.jar differ diff --git a/server/gradle/wrapper/gradle-wrapper.properties b/server/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..a4413138c --- /dev/null +++ b/server/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/server/gradlew b/server/gradlew new file mode 100644 index 000000000..b740cf133 --- /dev/null +++ b/server/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright ยฉ 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions ยซ$varยป, ยซ${var}ยป, ยซ${var:-default}ยป, ยซ${var+SET}ยป, +# ยซ${var#prefix}ยป, ยซ${var%suffix}ยป, and ยซ$( cmd )ยป; +# * compound commands having a testable exit status, especially ยซcaseยป; +# * various built-in commands including ยซcommandยป, ยซsetยป, and ยซulimitยป. +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/server/gradlew.bat b/server/gradlew.bat new file mode 100644 index 000000000..25da30dbd --- /dev/null +++ b/server/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/server/settings.gradle b/server/settings.gradle new file mode 100644 index 000000000..dbbee46fb --- /dev/null +++ b/server/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'haengdong' diff --git a/server/src/docs/asciidoc/billAction.adoc b/server/src/docs/asciidoc/billAction.adoc new file mode 100644 index 000000000..dfd7e26db --- /dev/null +++ b/server/src/docs/asciidoc/billAction.adoc @@ -0,0 +1,121 @@ +== ์ง€์ถœ ์•ก์…˜ + +=== ์ง€์ถœ ์•ก์…˜ ์ƒ์„ฑ + +operation::createBillActions[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"์ง€์ถœ ๊ธˆ์•ก์€ ๋น„์–ด ์žˆ์œผ๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค." + }, + { + "code":"REQUEST_EMPTY", + "message":"์ง€์ถœ ๋‚ด์—ญ์€ ๋น„์–ด ์žˆ์œผ๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค." + }, + { + "code":"BILL_ACTION_TITLE_INVALID", + "message":"์•ž๋’ค ๊ณต๋ฐฑ์„ ์ œ๊ฑฐํ•œ ์ง€์ถœ ๋‚ด์—ญ ์ œ๋ชฉ์€ %d ~ %d์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค." + }, + { + "code":"BILL_ACTION_PRICE_INVALID", + "message":"์ง€์ถœ ๊ธˆ์•ก์€ 10,000,000 ์ดํ•˜์˜ ์ž์—ฐ์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_EXPIRED", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_INVALID", + "message":"์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + } +] +---- + +=== ์ง€์ถœ ์•ก์…˜ ์ˆ˜์ • + +operation::updateBillAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"์ง€์ถœ ๋‚ด์—ญ ์ œ๋ชฉ์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + }, + { + "code":"REQUEST_EMPTY", + "message":"์ง€์ถœ ๊ธˆ์•ก์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + }, + { + "code":"BILL_ACTION_TITLE_INVALID", + "message":"์•ž๋’ค ๊ณต๋ฐฑ์„ ์ œ๊ฑฐํ•œ ์ง€์ถœ ๋‚ด์—ญ ์ œ๋ชฉ์€ %d ~ %d์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค." + }, + { + "code":"BILL_ACTION_PRICE_INVALID", + "message":"์ง€์ถœ ๊ธˆ์•ก์€ %,d ์ดํ•˜์˜ ์ž์—ฐ์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + }, + { + "code":"BILL_ACTION_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ง€์ถœ ์•ก์…˜์ž…๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_EXPIRED", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_INVALID", + "message":"์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + } +] +---- + +=== ์ง€์ถœ ์•ก์…˜ ์‚ญ์ œ + +operation::deleteBillAction[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_EXPIRED", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_INVALID", + "message":"์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + } +] +---- diff --git a/server/src/docs/asciidoc/billActionDetail.adoc b/server/src/docs/asciidoc/billActionDetail.adoc new file mode 100644 index 000000000..a8f19f21b --- /dev/null +++ b/server/src/docs/asciidoc/billActionDetail.adoc @@ -0,0 +1,93 @@ +== ์ง€์ถœ ์ƒ์„ธ + +=== ์ง€์ถœ ์ƒ์„ธ ์กฐํšŒ + +operation::findBillActionDetailsTest[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "EVENT_NOT_FOUND", + "message": "์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + }, + { + "code": "BILL_ACTION_NOT_FOUND", + "message": "์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ง€์ถœ ์•ก์…˜์ž…๋‹ˆ๋‹ค." + }, + { + "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "message": "์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ฐธ์—ฌ์ž ์ง€์ถœ์ž…๋‹ˆ๋‹ค." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code": "TOKEN_EXPIRED", + "message": "๋งŒ๋ฃŒ๋œ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + }, + { + "code": "TOKEN_INVALID", + "message": "์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + }, + { + "code": "FORBIDDEN", + "message": "์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + } +] +---- + +=== ์ง€์ถœ ์ƒ์„ธ ์ˆ˜์ • + +operation::updateBillActionDetailsTest[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "REQUEST_EMPTY", + "message": "๋ฉค๋ฒ„ ์ด๋ฆ„์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + }, + { + "code": "REQUEST_EMPTY", + "message": "์ง€์ถœ ๊ธˆ์•ก์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + }, + { + "code": "EVENT_NOT_FOUND", + "message": "์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + }, + { + "code": "BILL_ACTION_NOT_FOUND", + "message": "์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ง€์ถœ ์•ก์…˜์ž…๋‹ˆ๋‹ค." + }, + { + "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "message": "์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ฐธ์—ฌ์ž ์ง€์ถœ์ž…๋‹ˆ๋‹ค." + }, + { + "code": "BILL_ACTION_PRICE_NOT_MATCHED", + "message": "์ง€์ถœ ์ด์•ก์ด ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code": "TOKEN_EXPIRED", + "message": "๋งŒ๋ฃŒ๋œ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + }, + { + "code": "TOKEN_INVALID", + "message": "์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + }, + { + "code": "FORBIDDEN", + "message": "์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + } +] +---- diff --git a/server/src/docs/asciidoc/event.adoc b/server/src/docs/asciidoc/event.adoc new file mode 100644 index 000000000..72511b91b --- /dev/null +++ b/server/src/docs/asciidoc/event.adoc @@ -0,0 +1,205 @@ +== ํ–‰์‚ฌ + +=== ํ–‰์‚ฌ ์ƒ์„ฑ + +operation::createEvent[snippets="http-request,request-body,request-fields,response-body,response-fields,http-response,response-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"ํ–‰์‚ฌ ์ด๋ฆ„์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + }, + { + "code":"EVENT_NAME_LENGTH_INVALID", + "message":"ํ–‰์‚ฌ ์ด๋ฆ„์€ 2์ž ์ด์ƒ 30์ž ์ดํ•˜๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ์ด๋ฆ„ ๊ธธ์ด : 21" + }, + { + "code":"EVENT_NAME_MULTIPLE_BLANK", + "message":"ํ–‰์‚ฌ ์ด๋ฆ„์—๋Š” ๊ณต๋ฐฑ ๋ฌธ์ž๊ฐ€ ์—ฐ์†๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ์ด๋ฆ„ : ๊ณต๋ฐฑ ๋ฌธ์ž" + }, + { + "code":"EVENT_PASSWORD_INVALID", + "message":"๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” 4์ž๋ฆฌ ์ˆซ์ž๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค." + } +] +---- + +=== ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž ๋กœ๊ทธ์ธ + +operation::eventLogin[snippets="path-parameters,http-request,request-body,request-fields,http-response,response-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + }, + { + "code":"REQUEST_EMPTY", + "message":"๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + }, + { + "code":"PASSWORD_INVALID", + "message":"๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + } +] +---- + +=== ํ–‰์‚ฌ ์ •๋ณด ์กฐํšŒ + +operation::getEvent[snippets="path-parameters,http-request,response-body,response-fields,http-response"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + } +] +---- + +=== ํ–‰์‚ฌ ์ „์ฒด ์ฐธ์—ฌ์ž ๋ชฉ๋ก ์กฐํšŒ + +operation::findAllEventMember[snippets="path-parameters,http-request,response-body,response-fields,http-response,response-fields"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + } +] +---- + +=== ํ–‰์‚ฌ ์ „์ฒด ์•ก์…˜ ์ด๋ ฅ ์กฐํšŒ + +operation::findActions[snippets="path-parameters,http-request,http-response,response-fields"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + } +] +---- + +=== ํ–‰์‚ฌ ์ฐธ์—ฌ์ž ์ด๋ฆ„ ๋ณ€๊ฒฝ + +operation::updateEventMemberName[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + + { + "code":"MEMBER_NAME_CHANGE_DUPLICATE", + "message":"์ค‘๋ณต๋œ ์ฐธ์—ฌ ์ธ์› ์ด๋ฆ„ ๋ณ€๊ฒฝ ์š”์ฒญ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค." + }, + { + "code":"MEMBER_NOT_EXIST", + "message":"ํ˜„์žฌ ์ฐธ์—ฌํ•˜๊ณ  ์žˆ์ง€ ์•Š๋Š” ์ธ์›์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค." + }, + { + "code":"REQUEST_EMPTY", + "message":"๋ฉค๋ฒ„ ์ด๋ฆ„์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + }, + { + "code":"MEMBER_NAME_LENGTH_INVALID", + "message":"๋ฉค๋ฒ„ ์ด๋ฆ„์€ 1์ž ์ด์ƒ 4์ž ์ดํ•˜๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + }, + { + "code":"MEMBER_NAME_DUPLICATE", + "message":"์ค‘๋ณต๋œ ํ–‰์‚ฌ ์ฐธ์—ฌ ์ธ์› ์ด๋ฆ„์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_EXPIRED", + "message":"๋งŒ๋ฃŒ๋œ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_INVALID", + "message":"์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + } +] +---- + +=== ํ–‰์‚ฌ ์ฐธ์—ฌ์ž ์‚ญ์ œ (ํŠน์ • ์ฐธ์—ฌ์ž์˜ ๋ชจ๋“  ์ฐธ์—ฌ์ž ์•ก์…˜ ์‚ญ์ œ) + +operation::deleteAllMemberActionByName[snippets="path-parameters,http-request,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_EXPIRED", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_INVALID", + "message":"์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + } +] +---- + +=== ํ–‰์‚ฌ ์–ด๋“œ๋ฏผ ๊ถŒํ•œ ํ™•์ธ + +operation::authenticateEvent[snippets="http-request,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "EVENT_NOT_FOUND", + "message": "์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code": "TOKEN_EXPIRED", + "message": "๋งŒ๋ฃŒ๋œ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + }, + { + "code": "TOKEN_INVALID", + "message": "์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + }, + { + "code": "FORBIDDEN", + "message": "์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + } +] +---- diff --git a/server/src/docs/asciidoc/index.adoc b/server/src/docs/asciidoc/index.adoc new file mode 100644 index 000000000..8e1bcd2d0 --- /dev/null +++ b/server/src/docs/asciidoc/index.adoc @@ -0,0 +1,15 @@ +ifndef::snippets[] +:snippets: ../../build/generated-snippets +endif::[] += ํ–‰๋™๋Œ€์žฅ +:source-highlighter: highlightjs :hardbreaks: +:toc: left :doctype: book :icons: font :toc-title: ์ „์ฒด API ๋ชฉ๋ก :toclevels: 2 :sectlinks: +:sectnums: +:sectnumlevels: 2 + + +include::{docdir}/event.adoc[] +include::{docdir}/memberBillReport.adoc[] +include::{docdir}/memberAction.adoc[] +include::{docdir}/billAction.adoc[] +include::{docdir}/billActionDetail.adoc[] diff --git a/server/src/docs/asciidoc/memberAction.adoc b/server/src/docs/asciidoc/memberAction.adoc new file mode 100644 index 000000000..897102c8d --- /dev/null +++ b/server/src/docs/asciidoc/memberAction.adoc @@ -0,0 +1,100 @@ +== ์ฐธ์—ฌ์ž ์•ก์…˜ + +=== ์ฐธ์—ฌ์ž ์•ก์…˜ ์ƒ์„ฑ + +operation::createMemberAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"๋ฉค๋ฒ„ ์•ก์…˜์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + }, + { + "code":"MEMBER_ACTION_STATUS_INVALID", + "message":"๋ฉค๋ฒ„ ์•ก์…˜์€ IN, OUT๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ๋ฉค๋ฒ„ ์•ก์…˜: I_N" + }, + { + "code":"MEMBER_ALREADY_EXIST", + "message":"ํ˜„์žฌ ์ฐธ์—ฌํ•˜๊ณ  ์žˆ๋Š” ์ธ์›์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค." + }, + { + "code":"MEMBER_NOT_EXIST", + "message":"ํ˜„์žฌ ์ฐธ์—ฌํ•˜๊ณ  ์žˆ์ง€ ์•Š๋Š” ์ธ์›์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค." + }, + { + "code":"MEMBER_NAME_DUPLICATE", + "message":"์ค‘๋ณต๋œ ์ด๋ฆ„์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅ๋œ ์ด๋ฆ„: ์ด์ƒ, ์ด์ƒ, ๊ฐ์ž, ๋ฐฑํ˜ธ" + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_EXPIRED", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_INVALID", + "message":"์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + } +] +---- + +=== ํ˜„์žฌ ํ–‰์‚ฌ์— ์ฐธ์—ฌ ์ค‘์ธ (ํƒˆ์ฃผ ๊ฐ€๋Šฅํ•œ) ์ฐธ์—ฌ์ž ๋ชฉ๋ก ์กฐํšŒ + +operation::getCurrentMembers[snippets="path-parameters,http-request,http-response,response-fields"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + } +] +---- + +=== ์ฐธ์—ฌ์ž ์•ก์…˜ ์‚ญ์ œ + +operation::deleteMemberAction[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + }, + { + "code":"ACTION_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ์•ก์…˜์ž…๋‹ˆ๋‹ค." + }, + { + "code":"MEMBER_ACTION_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋ฉค๋ฒ„ ์•ก์…˜์ž…๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_EXPIRED", + "message":"ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." + }, + { + "code":"TOKEN_INVALID", + "message":"์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." + } +] +---- diff --git a/server/src/docs/asciidoc/memberBillReport.adoc b/server/src/docs/asciidoc/memberBillReport.adoc new file mode 100644 index 000000000..18bd7d3ef --- /dev/null +++ b/server/src/docs/asciidoc/memberBillReport.adoc @@ -0,0 +1,17 @@ +== ์ •์‚ฐ + +=== ์ฐธ์—ฌ์ž๋ณ„ ์ •์‚ฐ ๊ฒฐ๊ณผ ์กฐํšŒ + +operation::getMemberBillReports[snippets="path-parameters,http-request,response-body,response-fields,http-response,http-request"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค." + } +] +---- diff --git a/server/src/main/java/server/haengdong/HaengdongApplication.java b/server/src/main/java/server/haengdong/HaengdongApplication.java new file mode 100644 index 000000000..4a84c6120 --- /dev/null +++ b/server/src/main/java/server/haengdong/HaengdongApplication.java @@ -0,0 +1,15 @@ +package server.haengdong; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@Slf4j +@SpringBootApplication +public class HaengdongApplication { + + public static void main(String[] args) { + SpringApplication.run(HaengdongApplication.class, args); + } + +} diff --git a/server/src/main/java/server/haengdong/application/ActionService.java b/server/src/main/java/server/haengdong/application/ActionService.java new file mode 100644 index 000000000..bcf5e8b55 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/ActionService.java @@ -0,0 +1,39 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberBillReport; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class ActionService { + + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + + public List<MemberBillReportAppResponse> getMemberBillReports(String token) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + List<BillAction> billActions = billActionRepository.findByAction_Event(event); + List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); + + MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); + + return memberBillReport.getReports().entrySet().stream() + .map(entry -> new MemberBillReportAppResponse(entry.getKey(), entry.getValue())) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/application/AuthService.java b/server/src/main/java/server/haengdong/application/AuthService.java new file mode 100644 index 000000000..d9352ad53 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/AuthService.java @@ -0,0 +1,41 @@ +package server.haengdong.application; + + +import java.util.Map; +import server.haengdong.domain.TokenProvider; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; + +public class AuthService { + + private static final String TOKEN_NAME = "eventToken"; + private static final String CLAIM_SUB = "sub"; + + private final TokenProvider tokenProvider; + + public AuthService(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + public String createToken(String eventId) { + Map<String, Object> payload = Map.of(CLAIM_SUB, eventId); + + return tokenProvider.createToken(payload); + } + + public String findEventIdByToken(String token) { + validateToken(token); + Map<String, Object> payload = tokenProvider.getPayload(token); + return (String) payload.get(CLAIM_SUB); + } + + private void validateToken(String token) { + if (!tokenProvider.validateToken(token)) { + throw new AuthenticationException(HaengdongErrorCode.TOKEN_INVALID); + } + } + + public String getTokenName() { + return TOKEN_NAME; + } +} diff --git a/server/src/main/java/server/haengdong/application/BillActionDetailService.java b/server/src/main/java/server/haengdong/application/BillActionDetailService.java new file mode 100644 index 000000000..55d39aac0 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/BillActionDetailService.java @@ -0,0 +1,76 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class BillActionDetailService { + + private final BillActionRepository billActionRepository; + + public BillActionDetailsAppResponse findBillActionDetails(String token, Long actionId) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + validateToken(token, billAction); + + List<BillActionDetail> billActionDetails = billAction.getBillActionDetails(); + return BillActionDetailsAppResponse.of(billActionDetails); + } + + @Transactional + public void updateBillActionDetails(String token, Long actionId, BillActionDetailsUpdateAppRequest request) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + + List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests = request.billActionDetailUpdateAppRequests(); + + validateToken(token, billAction); + validateTotalPrice(billActionDetailUpdateAppRequests, billAction); + + List<BillActionDetail> billActionDetails = billAction.getBillActionDetails(); + + for (BillActionDetailUpdateAppRequest updateRequest : billActionDetailUpdateAppRequests) { + BillActionDetail detailToUpdate = billActionDetails.stream() + .filter(detail -> detail.isSameName(updateRequest.name())) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_DETAIL_NOT_FOUND)); + + detailToUpdate.updatePrice(updateRequest.price()); + detailToUpdate.updateIsFixed(updateRequest.isFixed()); + } + } + + private void validateToken(String token, BillAction billAction) { + Event event = billAction.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); + } + } + + private void validateTotalPrice(List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests, + BillAction billAction) { + Long requestsPriceSum = calculateUpdatePriceSum(billActionDetailUpdateAppRequests); + if (!billAction.isSamePrice(requestsPriceSum)) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_NOT_MATCHED); + } + } + + private Long calculateUpdatePriceSum(List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests) { + return billActionDetailUpdateAppRequests.stream() + .map(BillActionDetailUpdateAppRequest::price) + .reduce(0L, Long::sum); + } +} diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java new file mode 100644 index 000000000..dae36a2e7 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -0,0 +1,80 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.application.request.BillActionUpdateAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class BillActionService { + + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + private final ActionRepository actionRepository; + private final EventRepository eventRepository; + + @Transactional + public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) { + Event event = getEvent(eventToken); + Action action = createStartAction(event); + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); + + for (BillActionAppRequest request : requests) { + BillAction billAction = request.toBillAction(action, currentMembers); + billActionRepository.save(billAction); + action = action.next(); + } + } + + private Action createStartAction(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::next) + .orElse(Action.createFirst(event)); + } + + @Transactional + public void updateBillAction(String token, Long actionId, BillActionUpdateAppRequest request) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + + validateToken(token, billAction); + + billAction.update(request.title(), request.price()); + } + + private void validateToken(String token, BillAction billAction) { + Event event = billAction.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); + } + } + + @Transactional + public void deleteBillAction(String token, Long actionId) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + + billActionRepository.deleteByAction_EventAndActionId(event, actionId); + } + + private Event getEvent(String eventToken) { + return eventRepository.findByToken(eventToken) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } +} diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java new file mode 100644 index 000000000..1aaddd0f9 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -0,0 +1,170 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.EventLoginAppRequest; +import server.haengdong.application.request.MemberNameUpdateAppRequest; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class EventService { + + private final EventRepository eventRepository; + private final EventTokenProvider eventTokenProvider; + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + private final BillActionDetailRepository billActionDetailRepository; + + + @Transactional + public EventAppResponse saveEvent(EventAppRequest request) { + String token = eventTokenProvider.createToken(); + Event event = request.toEvent(token); + eventRepository.save(event); + + return EventAppResponse.of(event); + } + + public EventDetailAppResponse findEvent(String token) { + Event event = getEvent(token); + + return EventDetailAppResponse.of(event); + } + + public List<ActionAppResponse> findActions(String token) { + Event event = getEvent(token); + + List<BillAction> billActions = billActionRepository.findByAction_Event(event).stream() + .sorted(Comparator.comparing(BillAction::getSequence)).toList(); + List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event).stream() + .sorted(Comparator.comparing(MemberAction::getSequence)).toList(); + + return getActionAppResponses(billActions, memberActions); + } + + private List<ActionAppResponse> getActionAppResponses( + List<BillAction> billActions, + List<MemberAction> memberActions + ) { + int billActionIndex = 0; + int memberActionIndex = 0; + List<ActionAppResponse> actionAppResponses = new ArrayList<>(); + + while (billActionIndex < billActions.size() && memberActionIndex < memberActions.size()) { + BillAction billAction = billActions.get(billActionIndex); + MemberAction memberAction = memberActions.get(memberActionIndex); + if (billAction.getSequence() < memberAction.getSequence()) { + actionAppResponses.add(ActionAppResponse.of(billAction)); + billActionIndex++; + } else { + actionAppResponses.add(ActionAppResponse.of(memberAction)); + memberActionIndex++; + } + } + while (billActionIndex < billActions.size()) { + BillAction billAction = billActions.get(billActionIndex++); + actionAppResponses.add(ActionAppResponse.of(billAction)); + } + while (memberActionIndex < memberActions.size()) { + MemberAction memberAction = memberActions.get(memberActionIndex++); + actionAppResponses.add(ActionAppResponse.of(memberAction)); + } + + return actionAppResponses; + } + + public MembersAppResponse findAllMembers(String token) { + Event event = getEvent(token); + + List<String> memberNames = memberActionRepository.findAllUniqueMemberByEvent(event); + + return new MembersAppResponse(memberNames); + } + + @Transactional + public void updateMember(String token, MemberNamesUpdateAppRequest request) { + Event event = getEvent(token); + List<MemberNameUpdateAppRequest> members = request.members(); + + validateBeforeNames(members, event); + validateAfterNames(members, event); + + members.forEach(member -> updateMemberName(event, member.before(), member.after())); + } + + private void validateBeforeNames(List<MemberNameUpdateAppRequest> members, Event event) { + List<String> beforeNames = members.stream() + .map(MemberNameUpdateAppRequest::before) + .toList(); + if (beforeNames.size() != Set.copyOf(beforeNames).size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + beforeNames.forEach(beforeName -> validateBeforeMemberNameExist(event, beforeName)); + } + + private void validateBeforeMemberNameExist(Event event, String beforeName) { + boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, beforeName); + if (!isMemberNameExist) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); + } + } + + private void validateAfterNames(List<MemberNameUpdateAppRequest> members, Event event) { + List<String> afterNames = members.stream() + .map(MemberNameUpdateAppRequest::after) + .toList(); + if (afterNames.size() != Set.copyOf(afterNames).size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + afterNames.forEach(afterName -> validateAfterMemberNameNotExist(event, afterName)); + } + + private void validateAfterMemberNameNotExist(Event event, String afterName) { + boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, afterName); + if (isMemberNameExist) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + private void updateMemberName(Event event, String beforeName, String afterName) { + memberActionRepository.findAllByAction_EventAndMemberName(event, beforeName) + .forEach(memberAction -> memberAction.updateMemberName(afterName)); + billActionDetailRepository.findAllByBillAction_Action_EventAndMemberName(event, beforeName) + .forEach(billActionDetail -> billActionDetail.updateMemberName(afterName)); + } + + public void validatePassword(EventLoginAppRequest request) throws HaengdongException { + Event event = getEvent(request.token()); + if (event.isPasswordMismatch(request.password())) { + throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID); + } + } + + private Event getEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } +} diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java new file mode 100644 index 000000000..c0a171642 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -0,0 +1,62 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.MemberGroupIdProvider; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Component +public class MemberActionFactory { + + private final MemberGroupIdProvider memberGroupIdProvider; + + public List<MemberAction> createMemberActions( + MemberActionsSaveAppRequest request, + CurrentMembers currentMembers, + Action action + ) { + validateMemberNames(request); + validateActions(request, currentMembers); + + Long memberGroupId = memberGroupIdProvider.createGroupId(); + List<MemberAction> createdMemberActions = new ArrayList<>(); + List<MemberActionSaveAppRequest> actions = request.actions(); + for (MemberActionSaveAppRequest appRequest : actions) { + MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId); + createdMemberActions.add(memberAction); + action = action.next(); + } + + return createdMemberActions; + } + + private void validateMemberNames(MemberActionsSaveAppRequest request) { + List<String> memberNames = request.actions().stream() + .map(MemberActionSaveAppRequest::name) + .toList(); + + long uniqueCount = memberNames.stream().distinct().count(); + if (uniqueCount != memberNames.size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + private void validateActions(MemberActionsSaveAppRequest request, CurrentMembers currentMembers) { + List<MemberActionSaveAppRequest> actions = request.actions(); + + for (MemberActionSaveAppRequest action : actions) { + MemberActionStatus memberActionStatus = MemberActionStatus.of(action.status()); + currentMembers.validate(action.name(), memberActionStatus); + } + } +} diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java new file mode 100644 index 000000000..245de8cef --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -0,0 +1,100 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class MemberActionService { + + private final MemberActionFactory memberActionFactory; + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + private final ActionRepository actionRepository; + private final BillActionRepository billActionRepository; + + @Transactional + public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { + Event event = findEvent(token); + + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); + Action action = createStartAction(event); + List<MemberAction> memberActions = memberActionFactory.createMemberActions(request, currentMembers, action); + memberActionRepository.saveAll(memberActions); + } + + private Action createStartAction(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::next) + .orElse(Action.createFirst(event)); + } + + public List<CurrentMemberAppResponse> getCurrentMembers(String token) { + Event event = findEvent(token); + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); + + return currentMembers.getMembers() + .stream() + .map(CurrentMemberAppResponse::new) + .toList(); + } + + private Event findEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } + + @Transactional + public void deleteMember(String token, String memberName) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + + memberActionRepository.deleteAllByEventAndMemberName(event, memberName); + + List<BillAction> billActions = billActionRepository.findByAction_Event(event); + billActions.forEach(billAction -> resetBillAction(event, billAction)); + } + + @Transactional + public void deleteMemberAction(String token, Long actionId) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + Action action = actionRepository.findByIdAndEvent(actionId, event) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.ACTION_NOT_FOUND)); + MemberAction memberAction = memberActionRepository.findByAction(action) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_NOT_FOUND)); + + memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), + memberAction.getSequence()); + + List<BillAction> billActions = billActionRepository.findByEventAndGreaterThanSequence(event, + action.getSequence()); + billActions.forEach(billAction -> resetBillAction(event, billAction)); + } + + private void resetBillAction(Event event, BillAction billAction) { + List<MemberAction> memberActions = memberActionRepository.findByEventAndSequence(event, + billAction.getSequence()); + CurrentMembers currentMembers = CurrentMembers.of(memberActions); + + billAction.resetBillActionDetails(currentMembers); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java new file mode 100644 index 000000000..21eb17d4a --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java @@ -0,0 +1,15 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.CurrentMembers; + +public record BillActionAppRequest( + String title, + Long price +) { + + public BillAction toBillAction(Action action, CurrentMembers currentMembers) { + return BillAction.create(action, title, price, currentMembers); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java new file mode 100644 index 000000000..e514aee81 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +public record BillActionDetailUpdateAppRequest( + String name, + Long price, + boolean isFixed +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java new file mode 100644 index 000000000..1fe19798e --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record BillActionDetailsUpdateAppRequest( + List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java new file mode 100644 index 000000000..a90e3dd42 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java @@ -0,0 +1,7 @@ +package server.haengdong.application.request; + +public record BillActionUpdateAppRequest( + String title, + Long price +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java new file mode 100644 index 000000000..20ec16d88 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java @@ -0,0 +1,10 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.event.Event; + +public record EventAppRequest(String name, String password) { + + public Event toEvent(String token) { + return new Event(name, password, token); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java new file mode 100644 index 000000000..947b5ef39 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java @@ -0,0 +1,4 @@ +package server.haengdong.application.request; + +public record EventLoginAppRequest(String token, String password) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java new file mode 100644 index 000000000..f7f8d8fc2 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java @@ -0,0 +1,12 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; + +public record MemberActionSaveAppRequest(String name, String status) { + + public MemberAction toMemberAction(Action action, Long memberGroupId) { + return new MemberAction(action, name, MemberActionStatus.of(status), memberGroupId); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java new file mode 100644 index 000000000..650b908df --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java @@ -0,0 +1,6 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MemberActionsSaveAppRequest(List<MemberActionSaveAppRequest> actions) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java new file mode 100644 index 000000000..d629d3a02 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java @@ -0,0 +1,7 @@ +package server.haengdong.application.request; + +public record MemberNameUpdateAppRequest( + String before, + String after +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java new file mode 100644 index 000000000..cd0c00544 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MemberNamesUpdateAppRequest( + List<MemberNameUpdateAppRequest> members +) { +} diff --git a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java new file mode 100644 index 000000000..0c2c12611 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java @@ -0,0 +1,61 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; + +public record ActionAppResponse( + Long actionId, + String name, + Long price, + Long sequence, + boolean isFixed, + ActionType actionType +) { + + public ActionAppResponse(Long actionId, String name, Long price, Long sequence, ActionType actionType) { + this(actionId, name, price, sequence, false, actionType); + } + + public static ActionAppResponse of(BillAction billAction) { + return new ActionAppResponse( + billAction.getAction().getId(), + billAction.getTitle(), + billAction.getPrice(), + billAction.getSequence(), + billAction.isFixed(), + ActionAppResponse.ActionType.BILL + ); + } + + public static ActionAppResponse of(MemberAction memberAction) { + MemberActionStatus status = memberAction.getStatus(); + + return new ActionAppResponse( + memberAction.getAction().getId(), + memberAction.getMemberName(), + null, + memberAction.getSequence(), + false, + ActionAppResponse.ActionType.of(status) + ); + } + + public String actionTypeName() { + return actionType.name(); + } + + public enum ActionType { + BILL, + IN, + OUT, + ; + + private static ActionType of(MemberActionStatus memberActionStatus) { + if (MemberActionStatus.IN == memberActionStatus) { + return IN; + } + return OUT; + } + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java new file mode 100644 index 000000000..3efc7ac9d --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java @@ -0,0 +1,18 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.BillActionDetail; + +public record BillActionDetailAppResponse( + String name, + Long price, + boolean isFixed +) { + + public static BillActionDetailAppResponse of(BillActionDetail billActionDetail) { + return new BillActionDetailAppResponse( + billActionDetail.getMemberName(), + billActionDetail.getPrice(), + billActionDetail.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java new file mode 100644 index 000000000..061f07816 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.application.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.domain.action.BillActionDetail; + +public record BillActionDetailsAppResponse(List<BillActionDetailAppResponse> billActionDetailAppResponses) { + + public static BillActionDetailsAppResponse of(List<BillActionDetail> billActionDetails) { + return billActionDetails.stream() + .map(BillActionDetailAppResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsAppResponse::new)); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java new file mode 100644 index 000000000..6c682d3e9 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.MemberAction; + +public record CurrentMemberAppResponse(String name) { + + public static CurrentMemberAppResponse of(MemberAction memberAction) { + return new CurrentMemberAppResponse(memberAction.getMemberName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java new file mode 100644 index 000000000..f331d0011 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.event.Event; + +public record EventAppResponse(String token) { + + public static EventAppResponse of(Event event) { + return new EventAppResponse(event.getToken()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java new file mode 100644 index 000000000..6e38826d4 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.event.Event; + +public record EventDetailAppResponse(String eventName) { + + public static EventDetailAppResponse of(Event event) { + return new EventDetailAppResponse(event.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java new file mode 100644 index 000000000..21b6cef56 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java @@ -0,0 +1,4 @@ +package server.haengdong.application.response; + +public record MemberBillReportAppResponse(String name, Long price) { +} diff --git a/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java new file mode 100644 index 000000000..be8378b37 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java @@ -0,0 +1,8 @@ +package server.haengdong.application.response; + +import java.util.List; + +public record MembersAppResponse( + List<String> memberNames +) { +} diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java new file mode 100644 index 000000000..a0542ed46 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -0,0 +1,51 @@ +package server.haengdong.config; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import server.haengdong.application.AuthService; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.infrastructure.auth.AuthenticationExtractor; + +@Slf4j +public class AdminInterceptor implements HandlerInterceptor { + + private final AuthService authService; + private final AuthenticationExtractor authenticationExtractor; + + public AdminInterceptor(AuthService authService, AuthenticationExtractor authenticationExtractor) { + this.authService = authService; + this.authenticationExtractor = authenticationExtractor; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + String requestURI = request.getRequestURI(); + + if (requestURI.endsWith("/login")) { + return true; // ์š”์ฒญ์„ ๊ณ„์† ์ง„ํ–‰ํ•˜๋„๋ก ํ—ˆ์šฉ + } + + HttpMethod method = HttpMethod.valueOf(request.getMethod()); + if (HttpMethod.GET.equals(method) || HttpMethod.OPTIONS.equals(method)) { + return true; + } + + validateToken(request); + + return true; + } + + private void validateToken(HttpServletRequest request) { + String token = authenticationExtractor.extract(request, authService.getTokenName()); + String tokenEventId = authService.findEventIdByToken(token); + String eventId = request.getRequestURI().split("/")[3]; + if (!tokenEventId.equals(eventId)) { + log.warn("[ํ–‰์‚ฌ ์ ‘๊ทผ ๋ถˆ๊ฐ€] Cookie EventId = {}, URL EventId = {}", tokenEventId, eventId); + throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); + } + } +} diff --git a/server/src/main/java/server/haengdong/config/RequestServletFilter.java b/server/src/main/java/server/haengdong/config/RequestServletFilter.java new file mode 100644 index 000000000..b1afdb6f8 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/RequestServletFilter.java @@ -0,0 +1,23 @@ +package server.haengdong.config; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import java.io.IOException; +import org.springframework.stereotype.Component; +import org.springframework.web.util.ContentCachingRequestWrapper; + +@Component +public class RequestServletFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper((HttpServletRequest) request); + + chain.doFilter(wrappedRequest, response); + } +} diff --git a/server/src/main/java/server/haengdong/config/WebMvcConfig.java b/server/src/main/java/server/haengdong/config/WebMvcConfig.java new file mode 100644 index 000000000..d1caa176f --- /dev/null +++ b/server/src/main/java/server/haengdong/config/WebMvcConfig.java @@ -0,0 +1,66 @@ +package server.haengdong.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import server.haengdong.application.AuthService; +import server.haengdong.domain.TokenProvider; +import server.haengdong.infrastructure.auth.AuthenticationExtractor; +import server.haengdong.infrastructure.auth.JwtTokenProvider; +import server.haengdong.infrastructure.auth.TokenProperties; + +@RequiredArgsConstructor +@EnableConfigurationProperties(TokenProperties.class) +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + private final TokenProperties tokenProperties; + + @Value("${cors.max-age}") + private Long maxAge; + + @Value("${cors.allowed-origins}") + private String[] allowedOrigins; + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins(allowedOrigins) + .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") + .allowedHeaders("*") + .allowCredentials(true) + .maxAge(maxAge); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(adminInterceptor()) + .addPathPatterns("/api/**") + .excludePathPatterns("/api/events"); + } + + @Bean + public AdminInterceptor adminInterceptor() { + return new AdminInterceptor(authService(), authenticationExtractor()); + } + + @Bean + public AuthService authService() { + return new AuthService(tokenProvider()); + } + + @Bean + public TokenProvider tokenProvider() { + return new JwtTokenProvider(tokenProperties); + } + + @Bean + public AuthenticationExtractor authenticationExtractor() { + return new AuthenticationExtractor(); + } +} diff --git a/server/src/main/java/server/haengdong/domain/TokenProvider.java b/server/src/main/java/server/haengdong/domain/TokenProvider.java new file mode 100644 index 000000000..28e7956c3 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/TokenProvider.java @@ -0,0 +1,12 @@ +package server.haengdong.domain; + +import java.util.Map; + +public interface TokenProvider { + + String createToken(Map<String, Object> payload); + + Map<String, Object> getPayload(String token); + + boolean validateToken(String token); +} diff --git a/server/src/main/java/server/haengdong/domain/action/Action.java b/server/src/main/java/server/haengdong/domain/action/Action.java new file mode 100644 index 000000000..11f91fc38 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/Action.java @@ -0,0 +1,42 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Action { + + private static final long FIRST_SEQUENCE = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + private Long sequence; + + public Action(Event event, Long sequence) { + this.event = event; + this.sequence = sequence; + } + + public static Action createFirst(Event event) { + return new Action(event, FIRST_SEQUENCE); + } + + public Action next() { + return new Action(event, sequence + 1); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/ActionRepository.java b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java new file mode 100644 index 000000000..2fde0ffa6 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java @@ -0,0 +1,23 @@ +package server.haengdong.domain.action; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface ActionRepository extends JpaRepository<Action, Long> { + + @Query(""" + SELECT a + FROM Action a + WHERE a.event = :event + ORDER BY a.sequence DESC + LIMIT 1 + """) + Optional<Action> findLastByEvent(@Param("event") Event event); + + Optional<Action> findByIdAndEvent(Long id, Event event); +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java new file mode 100644 index 000000000..943b40ce5 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -0,0 +1,156 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class BillAction implements Comparable<BillAction> { + + public static final int MIN_TITLE_LENGTH = 1; + public static final int MAX_TITLE_LENGTH = 30; + public static final long MIN_PRICE = 1L; + public static final long MAX_PRICE = 10_000_000L; + private static final long DEFAULT_PRICE = 0L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + private Action action; + + @Column(length = MAX_TITLE_LENGTH) + private String title; + + private Long price; + + @OneToMany(mappedBy = "billAction", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private List<BillActionDetail> billActionDetails = new ArrayList<>(); + + public BillAction(Action action, String title, Long price) { + validateTitle(title); + validatePrice(price); + this.action = action; + this.title = title.trim(); + this.price = price; + } + + private void validateTitle(String title) { + int titleLength = title.trim().length(); + if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_TITLE_INVALID); + } + } + + private void validatePrice(Long price) { + if (price < MIN_PRICE || price > MAX_PRICE) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_INVALID); + } + } + + public static BillAction create(Action action, String title, Long price, CurrentMembers currentMembers) { + BillAction billAction = new BillAction(action, title, price); + billAction.resetBillActionDetails(currentMembers); + return billAction; + } + + public void resetBillActionDetails(CurrentMembers currentMembers) { + this.billActionDetails.clear(); + Iterator<Long> priceIterator = distributePrice(currentMembers.size()).iterator(); + + for (String member : currentMembers.getMembers()) { + BillActionDetail billActionDetail = new BillActionDetail(this, member, priceIterator.next(), false); + this.billActionDetails.add(billActionDetail); + } + } + + private void resetBillActionDetails() { + Iterator<Long> priceIterator = distributePrice(billActionDetails.size()).iterator(); + + billActionDetails.forEach(billActionDetail -> { + billActionDetail.updatePrice(priceIterator.next()); + billActionDetail.updateIsFixed(false); + }); + } + + private List<Long> distributePrice(int memberCount) { + if (memberCount == 0) { + return new ArrayList<>(); + } + long eachPrice = price / memberCount; + long remainder = price % memberCount; + + List<Long> results = Stream.generate(() -> eachPrice) + .limit(memberCount - 1) + .collect(Collectors.toList()); + results.add(eachPrice + remainder); + return results; + } + + public void update(String title, Long price) { + validateTitle(title); + validatePrice(price); + this.title = title.trim(); + this.price = price; + resetBillActionDetails(); + } + + public void addDetails(List<BillActionDetail> billActionDetails) { + billActionDetails.forEach(this::addDetail); + } + + private void addDetail(BillActionDetail billActionDetail) { + this.billActionDetails.add(billActionDetail); + billActionDetail.setBillAction(this); + } + + public boolean isFixed() { + return billActionDetails.stream() + .anyMatch(BillActionDetail::isFixed); + } + + public boolean isSamePrice(Long price) { + return this.price.equals(price); + } + + public Long findPriceByMemberName(String memberName) { + return billActionDetails.stream() + .filter(billActionDetail -> billActionDetail.hasMemberName(memberName)) + .map(BillActionDetail::getPrice) + .findFirst() + .orElse(DEFAULT_PRICE); + } + + public Long getSequence() { + return action.getSequence(); + } + + public Event getEvent() { + return action.getEvent(); + } + + @Override + public int compareTo(BillAction o) { + return Long.compare(this.getSequence(), o.getSequence()); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java new file mode 100644 index 000000000..ffdfe04a3 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -0,0 +1,61 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class BillActionDetail { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private BillAction billAction; + + private String memberName; + + private Long price; + + private boolean isFixed; + + public BillActionDetail(BillAction billAction, String memberName, Long price, boolean isFixed) { + this.billAction = billAction; + this.memberName = memberName; + this.price = price; + this.isFixed = isFixed; + } + + public void updatePrice(Long price) { + this.price = price; + } + + public void updateIsFixed(boolean isFixed) { + this.isFixed = isFixed; + } + + public void updateMemberName(String name) { + this.memberName = name; + } + + public boolean hasMemberName(String memberName) { + return this.memberName.equals(memberName); + } + + public boolean isSameName(String memberName) { + return this.memberName.equals(memberName); + } + + public void setBillAction(BillAction billAction) { + this.billAction = billAction; + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java new file mode 100644 index 000000000..05de55304 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -0,0 +1,20 @@ +package server.haengdong.domain.action; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface BillActionDetailRepository extends JpaRepository<BillActionDetail, Long> { + + @Query(""" + select bd + from BillActionDetail bd + where bd.billAction = :billAction + """) + List<BillActionDetail> findAllByBillAction(BillAction billAction); + + List<BillActionDetail> findAllByBillAction_Action_EventAndMemberName(Event event, String memberName); +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java new file mode 100644 index 000000000..817a63bf8 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java @@ -0,0 +1,27 @@ +package server.haengdong.domain.action; + +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface BillActionRepository extends JpaRepository<BillAction, Long> { + + @EntityGraph(attributePaths = {"action"}) + List<BillAction> findByAction_Event(Event event); + + void deleteByAction_EventAndActionId(Event event, Long actionId); + + Optional<BillAction> findByAction_Id(Long actionId); + + @Query(""" + select ba + from BillAction ba + where ba.action.event = :event and ba.action.sequence > :sequence + """) + List<BillAction> findByEventAndGreaterThanSequence(Event event, Long sequence); +} diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java new file mode 100644 index 000000000..ba380aae5 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java @@ -0,0 +1,81 @@ +package server.haengdong.domain.action; + +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public class CurrentMembers { + + private final Set<String> members; + + public CurrentMembers() { + this(new HashSet<>()); + } + + protected CurrentMembers(Set<String> members) { + this.members = members; + } + + public static CurrentMembers of(List<MemberAction> memberActions) { + List<MemberAction> sortedMemberActions = getSortedMemberActions(memberActions); + Set<String> members = new HashSet<>(); + for (MemberAction memberAction : sortedMemberActions) { + String member = memberAction.getMemberName(); + if (memberAction.isSameStatus(MemberActionStatus.IN)) { + members.add(member); + continue; + } + members.remove(member); + } + + return new CurrentMembers(members); + } + + private static List<MemberAction> getSortedMemberActions(List<MemberAction> memberActions) { + return memberActions.stream() + .sorted(Comparator.comparing(MemberAction::getSequence)) + .toList(); + } + + public CurrentMembers addMemberAction(MemberAction memberAction) { + String memberName = memberAction.getMemberName(); + + Set<String> currentMembers = new HashSet<>(members); + + if (memberAction.isIn()) { + currentMembers.add(memberName); + } else { + currentMembers.remove(memberName); + } + return new CurrentMembers(currentMembers); + } + + public void validate(String memberName, MemberActionStatus memberActionStatus) { + if (memberActionStatus == MemberActionStatus.IN && members.contains(memberName)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); + } + if (memberActionStatus == MemberActionStatus.OUT && !members.contains(memberName)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); + } + } + + public boolean isEmpty() { + return members.isEmpty(); + } + + public boolean isNotEmpty() { + return !members.isEmpty(); + } + + public int size() { + return members.size(); + } + + public Set<String> getMembers() { + return Collections.unmodifiableSet(members); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java new file mode 100644 index 000000000..3faf65bde --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberAction.java @@ -0,0 +1,76 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class MemberAction implements Comparable<MemberAction> { + + public static final int MIN_NAME_LENGTH = 1; + public static final int MAX_NAME_LENGTH = 4; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + private Action action; + + private String memberName; + + @Enumerated(EnumType.STRING) + private MemberActionStatus status; + + private Long memberGroupId; + + public MemberAction(Action action, String memberName, MemberActionStatus status, Long memberGroupId) { + validateMemberName(memberName); + this.action = action; + this.memberName = memberName; + this.status = status; + this.memberGroupId = memberGroupId; + } + + private void validateMemberName(String memberName) { + int memberLength = memberName.length(); + if (memberLength < MIN_NAME_LENGTH || memberLength > MAX_NAME_LENGTH) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID); + } + } + + public void updateMemberName(String memberName) { + validateMemberName(memberName); + this.memberName = memberName; + } + + public boolean isIn() { + return status == MemberActionStatus.IN; + } + + public boolean isSameStatus(MemberActionStatus memberActionStatus) { + return status == memberActionStatus; + } + + public Long getSequence() { + return action.getSequence(); + } + + @Override + public int compareTo(MemberAction o) { + return Long.compare(this.getSequence(), o.getSequence()); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java new file mode 100644 index 000000000..324ff9797 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -0,0 +1,53 @@ +package server.haengdong.domain.action; + +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface MemberActionRepository extends JpaRepository<MemberAction, Long> { + + @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") + List<MemberAction> findAllByEvent(@Param("event") Event event); + + @Query(""" + select distinct m.memberName + from MemberAction m + where m.action.event = :event + """) + List<String> findAllUniqueMemberByEvent(Event event); + + @Modifying + @Query(""" + delete + from MemberAction m + where m.memberName = :memberName and m.action.event = :event + """) + void deleteAllByEventAndMemberName(Event event, String memberName); + + Optional<MemberAction> findByAction(Action action); + + @Modifying + @Query(""" + delete + from MemberAction m + where m.memberName = :memberName and m.action.sequence >= :sequence + """) + void deleteAllByMemberNameAndMinSequence(String memberName, Long sequence); + + List<MemberAction> findAllByAction_EventAndMemberName(Event event, String memberName); + + boolean existsByAction_EventAndMemberName(Event event, String updatedMemberName); + + @Query(""" + select ma + from MemberAction ma + where ma.action.event = :event and ma.action.sequence < :sequence + """) + List<MemberAction> findByEventAndSequence(Event event, Long sequence); +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java new file mode 100644 index 000000000..76c5a66d4 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java @@ -0,0 +1,19 @@ +package server.haengdong.domain.action; + +import java.util.Arrays; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public enum MemberActionStatus { + IN, + OUT, + ; + + public static MemberActionStatus of(String status) { + return Arrays.stream(MemberActionStatus.values()) + .filter(s -> s.name().equals(status)) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID, + String.format(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID.getMessage(), status))); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java new file mode 100644 index 000000000..7a707b9d8 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java @@ -0,0 +1,75 @@ +package server.haengdong.domain.action; + +import static java.util.stream.Collectors.toMap; + +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.function.Function; +import lombok.Getter; + +@Getter +public class MemberBillReport { + + private final Map<String, Long> reports; + + private MemberBillReport(Map<String, Long> reports) { + this.reports = reports; + } + + public static MemberBillReport createByActions(List<BillAction> billActions, List<MemberAction> memberActions) { + PriorityQueue<BillAction> sortedBillActions = new PriorityQueue<>(billActions); + PriorityQueue<MemberAction> sortedMemberActions = new PriorityQueue<>(memberActions); + + Map<String, Long> memberBillReports = initReports(memberActions); + CurrentMembers currentMembers = new CurrentMembers(); + while (!sortedBillActions.isEmpty() && !sortedMemberActions.isEmpty()) { + if (isMemberActionTurn(sortedMemberActions, sortedBillActions)) { + MemberAction memberAction = sortedMemberActions.poll(); + currentMembers = currentMembers.addMemberAction(memberAction); + continue; + } + addBillAction(sortedBillActions, currentMembers, memberBillReports); + } + + while (!sortedBillActions.isEmpty()) { + addBillAction(sortedBillActions, currentMembers, memberBillReports); + } + + return new MemberBillReport(memberBillReports); + } + + private static Map<String, Long> initReports(List<MemberAction> memberActions) { + return memberActions.stream() + .map(MemberAction::getMemberName) + .distinct() + .collect(toMap(Function.identity(), i -> 0L)); + } + + private static boolean isMemberActionTurn( + PriorityQueue<MemberAction> memberActions, + PriorityQueue<BillAction> billActions + ) { + MemberAction memberAction = memberActions.peek(); + BillAction billAction = billActions.peek(); + + return memberAction.getSequence() < billAction.getSequence(); + } + + private static void addBillAction( + PriorityQueue<BillAction> sortedBillActions, + CurrentMembers currentMembers, + Map<String, Long> memberBillReports + ) { + BillAction billAction = sortedBillActions.poll(); + if (currentMembers.isEmpty()) { + return; + } + + for (String currentMember : currentMembers.getMembers()) { + Long currentPrice = billAction.findPriceByMemberName(currentMember); + Long price = memberBillReports.get(currentMember) + currentPrice; + memberBillReports.put(currentMember, price); + } + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java new file mode 100644 index 000000000..9e32bd733 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java @@ -0,0 +1,11 @@ +package server.haengdong.domain.action; + +import org.springframework.stereotype.Component; + +@Component +public class MemberGroupIdProvider { + + public Long createGroupId() { + return System.currentTimeMillis(); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java new file mode 100644 index 000000000..bb5d53dbc --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -0,0 +1,70 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Event { + + public static final int MIN_NAME_LENGTH = 1; + public static final int MAX_NAME_LENGTH = 20; + private static final String SPACES = " "; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + @Embedded + @AttributeOverride(name = "value", column = @Column(name = "password")) + private Password password; + + private String token; + + public Event(String name, String password, String token) { + validateName(name); + this.name = name; + this.password = new Password(password); + this.token = token; + } + + private void validateName(String name) { + int nameLength = name.trim().length(); + if (nameLength < MIN_NAME_LENGTH || MAX_NAME_LENGTH < nameLength) { + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_LENGTH_INVALID, + String.format("ํ–‰์‚ฌ ์ด๋ฆ„์€ %d์ž ์ด์ƒ %d์ž ์ดํ•˜๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ์ด๋ฆ„ ๊ธธ์ด : %d", + MIN_NAME_LENGTH, + MAX_NAME_LENGTH, + name.length())); + } + if (isBlankContinuous(name)) { + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_CONSECUTIVE_SPACES, + String.format("ํ–‰์‚ฌ ์ด๋ฆ„์—๋Š” ๊ณต๋ฐฑ ๋ฌธ์ž๊ฐ€ ์—ฐ์†๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ์ด๋ฆ„ : %s", name)); + } + } + + private boolean isBlankContinuous(String name) { + return name.contains(SPACES); + } + + public boolean isTokenMismatch(String token) { + return !this.token.equals(token); + } + + public boolean isPasswordMismatch(String rawPassword) { + return !password.matches(rawPassword); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventRepository.java b/server/src/main/java/server/haengdong/domain/event/EventRepository.java new file mode 100644 index 000000000..09526125e --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventRepository.java @@ -0,0 +1,11 @@ +package server.haengdong.domain.event; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface EventRepository extends JpaRepository<Event, Long> { + + Optional<Event> findByToken(String token); +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventStep.java b/server/src/main/java/server/haengdong/domain/event/EventStep.java new file mode 100644 index 000000000..297abdb66 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventStep.java @@ -0,0 +1,28 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class EventStep { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + private String name; + + private Long sequence; +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java b/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java new file mode 100644 index 000000000..6450f0dcf --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java @@ -0,0 +1,12 @@ +package server.haengdong.domain.event; + +import java.util.UUID; +import org.springframework.stereotype.Component; + +@Component +public class EventTokenProvider { + + public String createToken() { + return UUID.randomUUID().toString(); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/Password.java b/server/src/main/java/server/haengdong/domain/event/Password.java new file mode 100644 index 000000000..375849dbf --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/Password.java @@ -0,0 +1,52 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.Embeddable; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@Embeddable +public class Password { + + public static final int PASSWORD_LENGTH = 4; + private static final Pattern PASSWORD_PATTERN = Pattern.compile(String.format("^\\d{%d}$", PASSWORD_LENGTH)); + private static final String HASH_ALGORITHM = "SHA-256"; + + private String value; + + public Password(String password) { + validatePassword(password); + this.value = encode(password); + } + + private void validatePassword(String password) { + Matcher matcher = PASSWORD_PATTERN.matcher(password); + if (!matcher.matches()) { + throw new HaengdongException(HaengdongErrorCode.EVENT_PASSWORD_FORMAT_INVALID); + } + } + + private String encode(String rawPassword) { + try { + MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM); + byte[] hashedPassword = digest.digest(rawPassword.getBytes()); + return Base64.getEncoder().encodeToString(hashedPassword); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("ํ•ด์‹œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + } + + public boolean matches(String rawPassword) { + String hashedPassword = encode(rawPassword); + return value.equals(hashedPassword); + } +} diff --git a/server/src/main/java/server/haengdong/exception/AuthenticationException.java b/server/src/main/java/server/haengdong/exception/AuthenticationException.java new file mode 100644 index 000000000..2efcb16e7 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/AuthenticationException.java @@ -0,0 +1,19 @@ +package server.haengdong.exception; + +import lombok.Getter; + +@Getter +public class AuthenticationException extends RuntimeException { + + private final HaengdongErrorCode errorCode; + private final String message; + + public AuthenticationException(HaengdongErrorCode errorCode) { + this(errorCode, errorCode.getMessage()); + } + + public AuthenticationException(HaengdongErrorCode errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/server/src/main/java/server/haengdong/exception/ErrorResponse.java b/server/src/main/java/server/haengdong/exception/ErrorResponse.java new file mode 100644 index 000000000..d0a2b01a0 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/ErrorResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.exception; + +public record ErrorResponse( + HaengdongErrorCode errorCode, + String message +) { + + public static ErrorResponse of(HaengdongErrorCode errorCode) { + return new ErrorResponse(errorCode, errorCode.getMessage()); + } + + public static ErrorResponse of(HaengdongErrorCode errorCode, String message) { + return new ErrorResponse(errorCode, message); + } +} diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java new file mode 100644 index 000000000..0cee7cb4c --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -0,0 +1,90 @@ +package server.haengdong.exception; + +import jakarta.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.resource.NoResourceFoundException; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + private static final String LOG_FORMAT = """ + \n\t{ + "RequestURI": "{} {}", + "RequestBody": {}, + "ErrorMessage": "{}" + \t} + """; + + @ExceptionHandler(AuthenticationException.class) + public ResponseEntity<ErrorResponse> authenticationException(HttpServletRequest req, AuthenticationException e) { + log.warn(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body(ErrorResponse.of(e.getErrorCode())); + } + + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public ResponseEntity<ErrorResponse> noResourceException(HttpRequestMethodNotSupportedException e) { + log.warn(e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.REQUEST_METHOD_NOT_SUPPORTED)); + } + + @ExceptionHandler(NoResourceFoundException.class) + public ResponseEntity<ErrorResponse> noResourceException(NoResourceFoundException e) { + log.warn(e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.NO_RESOURCE_REQUEST)); + } + + @ExceptionHandler(HttpMessageNotReadableException.class) + public ResponseEntity<ErrorResponse> httpMessageNotReadableException(HttpMessageNotReadableException e) { + log.warn(e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.MESSAGE_NOT_READABLE)); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + log.warn(e.getMessage(), e); + String errorMessage = e.getFieldErrors().stream() + .map(error -> error.getField() + " " + error.getDefaultMessage()) + .collect(Collectors.joining(", ")); + + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.REQUEST_EMPTY, errorMessage)); + } + + @ExceptionHandler(HaengdongException.class) + public ResponseEntity<ErrorResponse> haengdongException(HttpServletRequest req, HaengdongException e) { + log.warn(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(e.getErrorCode())); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity<ErrorResponse> handleException(HttpServletRequest req, Exception e) { + log.error(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); + return ResponseEntity.internalServerError() + .body(ErrorResponse.of(HaengdongErrorCode.INTERNAL_SERVER_ERROR)); + } + + private String getRequestBody(HttpServletRequest req) { + try (BufferedReader reader = req.getReader()) { + return reader.lines().collect(Collectors.joining(System.lineSeparator() + "\t")); + } catch (IOException e) { + log.error("Failed to read request body", e); + return ""; + } + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java new file mode 100644 index 000000000..475d16c11 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -0,0 +1,69 @@ +package server.haengdong.exception; + +import lombok.Getter; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.Password; + +@Getter +public enum HaengdongErrorCode { + + /* Domain */ + + EVENT_NOT_FOUND("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค."), + EVENT_NAME_LENGTH_INVALID(String.format("ํ–‰์‚ฌ ์ด๋ฆ„์€ %d์ž ์ด์ƒ %d์ž ์ดํ•˜๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.", + Event.MIN_NAME_LENGTH, + Event.MAX_NAME_LENGTH)), + EVENT_NAME_CONSECUTIVE_SPACES("ํ–‰์‚ฌ ์ด๋ฆ„์—๋Š” ๊ณต๋ฐฑ ๋ฌธ์ž๊ฐ€ ์—ฐ์†๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ์ด๋ฆ„ : %s"), + EVENT_PASSWORD_FORMAT_INVALID(String.format("๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” %d์ž๋ฆฌ ์ˆซ์ž๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.", Password.PASSWORD_LENGTH)), + + ACTION_NOT_FOUND("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์•ก์…˜์ž…๋‹ˆ๋‹ค."), + + MEMBER_NAME_LENGTH_INVALID(String.format("๋ฉค๋ฒ„ ์ด๋ฆ„์€ %d์ž ์ด์ƒ %d์ž ์ดํ•˜๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.", + MemberAction.MIN_NAME_LENGTH, + MemberAction.MAX_NAME_LENGTH)), + MEMBER_NAME_DUPLICATE("์ค‘๋ณต๋œ ํ–‰์‚ฌ ์ฐธ์—ฌ ์ธ์› ์ด๋ฆ„์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค."), + MEMBER_NOT_EXIST("ํ˜„์žฌ ์ฐธ์—ฌํ•˜๊ณ  ์žˆ์ง€ ์•Š๋Š” ์ธ์›์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค."), + MEMBER_ALREADY_EXIST("ํ˜„์žฌ ์ฐธ์—ฌํ•˜๊ณ  ์žˆ๋Š” ์ธ์›์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค."), + MEMBER_NAME_CHANGE_DUPLICATE("์ค‘๋ณต๋œ ์ฐธ์—ฌ ์ธ์› ์ด๋ฆ„ ๋ณ€๊ฒฝ ์š”์ฒญ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค."), + + MEMBER_ACTION_NOT_FOUND("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋ฉค๋ฒ„ ์•ก์…˜์ž…๋‹ˆ๋‹ค."), + MEMBER_ACTION_STATUS_INVALID("๋ฉค๋ฒ„ ์•ก์…˜์€ IN, OUT๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ๋ฉค๋ฒ„ ์•ก์…˜: %s"), + + BILL_ACTION_NOT_FOUND("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ง€์ถœ ์•ก์…˜์ž…๋‹ˆ๋‹ค."), + BILL_ACTION_TITLE_INVALID(String.format("์•ž๋’ค ๊ณต๋ฐฑ์„ ์ œ๊ฑฐํ•œ ์ง€์ถœ ๋‚ด์—ญ ์ œ๋ชฉ์€ %d ~ %d์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.", + BillAction.MIN_TITLE_LENGTH, + BillAction.MAX_TITLE_LENGTH)), + BILL_ACTION_PRICE_INVALID(String.format("์ง€์ถœ ๊ธˆ์•ก์€ %,d ์ดํ•˜์˜ ์ž์—ฐ์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.", BillAction.MAX_PRICE)), + BILL_ACTION_DETAIL_NOT_FOUND("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ฐธ์—ฌ์ž ์ง€์ถœ์ž…๋‹ˆ๋‹ค."), + BILL_ACTION_PRICE_NOT_MATCHED("์ง€์ถœ ์ด์•ก์ด ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."), + + /* Authentication */ + + PASSWORD_INVALID("๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."), + + TOKEN_NOT_FOUND("ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."), + TOKEN_EXPIRED("๋งŒ๋ฃŒ๋œ ํ† ํฐ์ž…๋‹ˆ๋‹ค."), + TOKEN_INVALID("์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค."), + + FORBIDDEN("์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ํ–‰์‚ฌ์ž…๋‹ˆ๋‹ค."), + + /* Request Validation */ + + REQUEST_EMPTY("์ž…๋ ฅ ๊ฐ’์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + + /* System */, + + MESSAGE_NOT_READABLE("์ฝ์„ ์ˆ˜ ์—†๋Š” ์š”์ฒญ์ž…๋‹ˆ๋‹ค."), + REQUEST_METHOD_NOT_SUPPORTED("์ง€์›ํ•˜์ง€ ์•Š๋Š” ์š”์ฒญ ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค."), + NO_RESOURCE_REQUEST("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ž์›์ž…๋‹ˆ๋‹ค."), + INTERNAL_SERVER_ERROR("์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."), + ; + + private final String message; + + HaengdongErrorCode(String message) { + this.message = message; + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongException.java b/server/src/main/java/server/haengdong/exception/HaengdongException.java new file mode 100644 index 000000000..b86fe4ffc --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/HaengdongException.java @@ -0,0 +1,19 @@ +package server.haengdong.exception; + +import lombok.Getter; + +@Getter +public class HaengdongException extends RuntimeException { + + private final HaengdongErrorCode errorCode; + private final String message; + + public HaengdongException(HaengdongErrorCode errorCode) { + this(errorCode, errorCode.getMessage()); + } + + public HaengdongException(HaengdongErrorCode errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java b/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java new file mode 100644 index 000000000..4972de48a --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java @@ -0,0 +1,23 @@ +package server.haengdong.infrastructure.auth; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import java.util.Arrays; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; + +public class AuthenticationExtractor { + + public String extract(HttpServletRequest request, String cookieName) { + Cookie[] cookies = request.getCookies(); + if (cookies == null) { + throw new AuthenticationException(HaengdongErrorCode.TOKEN_NOT_FOUND); + } + + return Arrays.stream(cookies) + .filter(cookie -> cookieName.equals(cookie.getName())) + .findFirst() + .orElseThrow(() -> new AuthenticationException(HaengdongErrorCode.TOKEN_NOT_FOUND)) + .getValue(); + } +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java b/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java new file mode 100644 index 000000000..18f867601 --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java @@ -0,0 +1,15 @@ +package server.haengdong.infrastructure.auth; + +import java.time.Duration; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("cookie") +public record CookieProperties( + boolean httpOnly, + boolean secure, + String domain, + String path, + String sameSite, + Duration maxAge +) { +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java b/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java new file mode 100644 index 000000000..df9ec6a81 --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java @@ -0,0 +1,54 @@ +package server.haengdong.infrastructure.auth; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import server.haengdong.domain.TokenProvider; + +public class JwtTokenProvider implements TokenProvider { + + private final TokenProperties tokenProperties; + + public JwtTokenProvider(TokenProperties tokenProperties) { + this.tokenProperties = tokenProperties; + } + + @Override + public String createToken(Map<String, Object> payload) { + Claims claims = Jwts.claims(new HashMap<>(payload)); + Date now = new Date(); + Date validity = new Date(now.getTime() + tokenProperties.expireLength()); + + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(validity) + .signWith(SignatureAlgorithm.HS256, tokenProperties.secretKey()) + .compact(); + } + + @Override + public Map<String, Object> getPayload(String token) { + return Jwts.parser() + .setSigningKey(tokenProperties.secretKey()) + .parseClaimsJws(token) + .getBody(); + } + + @Override + public boolean validateToken(String token) { + try { + Jws<Claims> claims = Jwts.parser().setSigningKey(tokenProperties.secretKey()).parseClaimsJws(token); + + return !claims.getBody().getExpiration().before(new Date()); + } catch (JwtException | IllegalArgumentException e) { + return false; + } + } +} + diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java b/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java new file mode 100644 index 000000000..11dedcdbf --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java @@ -0,0 +1,7 @@ +package server.haengdong.infrastructure.auth; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("security.jwt.token") +public record TokenProperties(String secretKey, Long expireLength) { +} diff --git a/server/src/main/java/server/haengdong/presentation/ActionController.java b/server/src/main/java/server/haengdong/presentation/ActionController.java new file mode 100644 index 000000000..657cb567e --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/ActionController.java @@ -0,0 +1,26 @@ +package server.haengdong.presentation; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.ActionService; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.presentation.response.MemberBillReportsResponse; + +@RequiredArgsConstructor +@RestController +public class ActionController { + + private final ActionService actionService; + + @GetMapping("/api/events/{eventId}/actions/reports") + public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("eventId") String token) { + List<MemberBillReportAppResponse> memberBillReports = actionService.getMemberBillReports(token); + + return ResponseEntity.ok() + .body(MemberBillReportsResponse.of(memberBillReports)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/BillActionController.java new file mode 100644 index 000000000..56e99337d --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/BillActionController.java @@ -0,0 +1,55 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillActionService; +import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +@RequiredArgsConstructor +@RestController +public class BillActionController { + + private final BillActionService billActionService; + + @PostMapping("/api/events/{eventId}/bill-actions") + public ResponseEntity<Void> saveAllBillAction( + @PathVariable("eventId") String token, + @Valid @RequestBody BillActionsSaveRequest request + ) { + billActionService.saveAllBillAction(token, request.toAppRequests()); + + return ResponseEntity.ok() + .build(); + } + + @PutMapping("/api/events/{eventId}/bill-actions/{actionId}") + public ResponseEntity<Void> updateBillAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId, + @Valid @RequestBody BillActionUpdateRequest request + ) { + billActionService.updateBillAction(token, actionId, request.toAppResponse()); + + return ResponseEntity.ok() + .build(); + } + + @DeleteMapping("/api/events/{eventId}/bill-actions/{actionId}") + public ResponseEntity<Void> deleteBillAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + billActionService.deleteBillAction(token, actionId); + + return ResponseEntity.ok() + .build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java new file mode 100644 index 000000000..5602e6777 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java @@ -0,0 +1,42 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillActionDetailService; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; +import server.haengdong.presentation.response.BillActionDetailsResponse; + +@RequiredArgsConstructor +@RestController +public class BillActionDetailController { + + private final BillActionDetailService billActionDetailService; + + @GetMapping("/api/events/{eventId}/bill-actions/{actionId}/fixed") + public ResponseEntity<BillActionDetailsResponse> findBillActionDetails( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + BillActionDetailsAppResponse appResponse = billActionDetailService.findBillActionDetails(token, actionId); + + return ResponseEntity.ok(BillActionDetailsResponse.of(appResponse)); + } + + @PutMapping("/api/events/{eventId}/bill-actions/{actionId}/fixed") + public ResponseEntity<Void> updateBillActionDetails( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId, + @Valid @RequestBody BillActionDetailsUpdateRequest request + ) { + billActionDetailService.updateBillActionDetails(token, actionId, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java new file mode 100644 index 000000000..34261042f --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -0,0 +1,120 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseCookie; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.AuthService; +import server.haengdong.application.EventService; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.infrastructure.auth.CookieProperties; +import server.haengdong.presentation.request.EventLoginRequest; +import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; +import server.haengdong.presentation.response.ActionsResponse; +import server.haengdong.presentation.response.EventDetailResponse; +import server.haengdong.presentation.response.EventResponse; +import server.haengdong.presentation.response.MembersResponse; +import server.haengdong.presentation.response.StepsResponse; + +@Slf4j +@RequiredArgsConstructor +@EnableConfigurationProperties(CookieProperties.class) +@RestController +public class EventController { + + private final EventService eventService; + private final AuthService authService; + private final CookieProperties cookieProperties; + + @PostMapping("/api/events") + public ResponseEntity<EventResponse> saveEvent(@Valid @RequestBody EventSaveRequest request) { + EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); + + String jwtToken = authService.createToken(eventResponse.eventId()); + + ResponseCookie responseCookie = createResponseCookie(jwtToken); + return ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) + .body(eventResponse); + } + + @GetMapping("/api/events/{eventId}") + public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("eventId") String token) { + EventDetailResponse eventDetailResponse = EventDetailResponse.of(eventService.findEvent(token)); + + return ResponseEntity.ok(eventDetailResponse); + } + + @GetMapping("/api/events/{eventId}/actions") + public ResponseEntity<StepsResponse> findActions(@PathVariable("eventId") String token) { + StepsResponse stepsResponse = StepsResponse.of(eventService.findActions(token)); + + return ResponseEntity.ok(stepsResponse); + } + + @GetMapping("/api/events/{eventId}/actions/v2") + public ResponseEntity<ActionsResponse> findActions2(@PathVariable("eventId") String token) { + List<ActionAppResponse> actions = eventService.findActions(token); + ActionsResponse actionsResponse = ActionsResponse.of(actions); + + return ResponseEntity.ok(actionsResponse); + } + + @GetMapping("/api/events/{eventId}/members") + public ResponseEntity<MembersResponse> findAllMembers(@PathVariable("eventId") String token) { + MembersResponse response = MembersResponse.of(eventService.findAllMembers(token)); + + return ResponseEntity.ok(response); + } + + @PutMapping("/api/events/{eventId}/members/nameChange") + public ResponseEntity<Void> updateMember( + @PathVariable("eventId") String token, + @Valid @RequestBody MemberNamesUpdateRequest request + ) { + eventService.updateMember(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @PostMapping("/api/events/{eventId}/login") + public ResponseEntity<Void> loginEvent( + @PathVariable("eventId") String token, + @Valid @RequestBody EventLoginRequest request + ) { + eventService.validatePassword(request.toAppRequest(token)); + String jwtToken = authService.createToken(token); + + ResponseCookie responseCookie = createResponseCookie(jwtToken); + return ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) + .build(); + } + + @PostMapping("/api/events/{eventId}/auth") + public ResponseEntity<Void> authenticate(@PathVariable("eventId") String token) { + return ResponseEntity.ok().build(); + } + + private ResponseCookie createResponseCookie(String token) { + return ResponseCookie.from(authService.getTokenName(), token) + .httpOnly(cookieProperties.httpOnly()) + .secure(cookieProperties.secure()) + .domain(cookieProperties.domain()) + .path(cookieProperties.path()) + .sameSite(cookieProperties.sameSite()) + .maxAge(cookieProperties.maxAge()) + .build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java new file mode 100644 index 000000000..1703245f7 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -0,0 +1,60 @@ +package server.haengdong.presentation; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.MemberActionService; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.request.MemberActionsSaveRequest; +import server.haengdong.presentation.response.CurrentMembersResponse; + +@RequiredArgsConstructor +@RestController +public class MemberActionController { + + private final MemberActionService memberActionService; + + @PostMapping("/api/events/{eventId}/member-actions") + public ResponseEntity<Void> saveMemberAction( + @PathVariable("eventId") String token, + @RequestBody MemberActionsSaveRequest request + ) { + memberActionService.saveMemberAction(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @GetMapping("/api/events/{eventId}/members/current") + public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("eventId") String token) { + List<CurrentMemberAppResponse> currentMembers = memberActionService.getCurrentMembers(token); + + return ResponseEntity.ok() + .body(CurrentMembersResponse.of(currentMembers)); + } + + @DeleteMapping("/api/events/{eventId}/members/{memberName}") + public ResponseEntity<Void> deleteMember( + @PathVariable("eventId") String token, + @PathVariable("memberName") String memberName + ) { + memberActionService.deleteMember(token, memberName); + + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/api/events/{eventId}/member-actions/{actionId}") + public ResponseEntity<Void> deleteMemberAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + memberActionService.deleteMemberAction(token, actionId); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java new file mode 100644 index 000000000..21c4bd60f --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java @@ -0,0 +1,21 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; + +public record BillActionDetailUpdateRequest( + + @NotBlank(message = "๋งด๋ฒ„ ์ด๋ฆ„์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String name, + + @NotNull(message = "์ง€์ถœ ๊ธˆ์•ก์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + Long price, + + @NotNull(message = "์ง€์ถœ ๊ธˆ์•ก์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + boolean isFixed +) { + public BillActionDetailUpdateAppRequest toAppRequest() { + return new BillActionDetailUpdateAppRequest(this.name, this.price, this.isFixed); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java new file mode 100644 index 000000000..fafbb8fd7 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; + +public record BillActionDetailsUpdateRequest( + @Valid @NotEmpty List<BillActionDetailUpdateRequest> members +) { + public BillActionDetailsUpdateAppRequest toAppRequest() { + return new BillActionDetailsUpdateAppRequest(members.stream() + .map(BillActionDetailUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java new file mode 100644 index 000000000..a47ff8316 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java @@ -0,0 +1,19 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionAppRequest; + +public record BillActionSaveRequest( + + @NotBlank(message = "์ง€์ถœ ๋‚ด์—ญ ์ œ๋ชฉ์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String title, + + @NotNull(message = "์ง€์ถœ ๊ธˆ์•ก์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + Long price +) { + + public BillActionAppRequest toAppRequest() { + return new BillActionAppRequest(title, price); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java new file mode 100644 index 000000000..680006816 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionUpdateAppRequest; + +public record BillActionUpdateRequest( + + @NotBlank(message = "์ง€์ถœ ๋‚ด์—ญ ์ œ๋ชฉ์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String title, + + @NotNull(message = "์ง€์ถœ ๊ธˆ์•ก์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + Long price +) { + public BillActionUpdateAppRequest toAppResponse() { + return new BillActionUpdateAppRequest(title, price); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java new file mode 100644 index 000000000..6727d4cf1 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.BillActionAppRequest; + +public record BillActionsSaveRequest( + + @Valid @NotEmpty List<BillActionSaveRequest> actions +) { + + public List<BillActionAppRequest> toAppRequests() { + return actions.stream() + .map(BillActionSaveRequest::toAppRequest) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java new file mode 100644 index 000000000..a1286e903 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.EventLoginAppRequest; + +public record EventLoginRequest( + + @NotBlank(message = "๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String password +) { + public EventLoginAppRequest toAppRequest(String token) { + return new EventLoginAppRequest(token, password); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java new file mode 100644 index 000000000..6bd7cd006 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.EventAppRequest; + +public record EventSaveRequest( + + @NotBlank(message = "ํ–‰์‚ฌ ์ด๋ฆ„์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String eventName, + + @NotBlank(message = "๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String password +) { + + public EventAppRequest toAppRequest() { + return new EventAppRequest(eventName, password); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java new file mode 100644 index 000000000..41e95cc3c --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java @@ -0,0 +1,25 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; + +public record MemberActionsSaveRequest( + + @NotEmpty + List<String> members, + + @NotBlank(message = "๋ฉค๋ฒ„ ์•ก์…˜์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String status +) { + + public MemberActionsSaveAppRequest toAppRequest() { + List<MemberActionSaveAppRequest> appRequests = members.stream() + .map(name -> new MemberActionSaveAppRequest(name, status)) + .toList(); + + return new MemberActionsSaveAppRequest(appRequests); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java new file mode 100644 index 000000000..3cd2294ca --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.MemberNameUpdateAppRequest; + +public record MemberNameUpdateRequest( + + @NotBlank(message = "๋ฉค๋ฒ„ ์ด๋ฆ„์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String before, + + @NotBlank(message = "๋ฉค๋ฒ„ ์ด๋ฆ„์€ ๊ณต๋ฐฑ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String after +) { + + public MemberNameUpdateAppRequest toAppRequest() { + return new MemberNameUpdateAppRequest(before, after); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java new file mode 100644 index 000000000..872aa55de --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java @@ -0,0 +1,17 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; + +public record MemberNamesUpdateRequest( + @Valid @NotEmpty List<MemberNameUpdateRequest> members +) { + + public MemberNamesUpdateAppRequest toAppRequest() { + return new MemberNamesUpdateAppRequest(members.stream() + .map(MemberNameUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java new file mode 100644 index 000000000..ea26ea769 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java @@ -0,0 +1,26 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.ActionAppResponse; + +public record ActionResponse( + Long actionId, + String name, + Long price, + Long sequence, + boolean isFixed +) { + + public ActionResponse(Long actionId, String name, Long price, Long sequence) { + this(actionId, name, price, sequence, false); + } + + public static ActionResponse of(ActionAppResponse actionAppResponse) { + return new ActionResponse( + actionAppResponse.actionId(), + actionAppResponse.name(), + actionAppResponse.price(), + actionAppResponse.sequence(), + actionAppResponse.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java new file mode 100644 index 000000000..ea46c5bd9 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java @@ -0,0 +1,22 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.ActionAppResponse; + +public record ActionResponse2( + Long actionId, + String name, + Long price, + Long sequence, + String type +) { + + public static ActionResponse2 of(ActionAppResponse actionAppResponse) { + return new ActionResponse2( + actionAppResponse.actionId(), + actionAppResponse.name(), + actionAppResponse.price(), + actionAppResponse.sequence(), + actionAppResponse.actionType().name() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java new file mode 100644 index 000000000..c8ae780e3 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; + +public record ActionsResponse( + List<ActionResponse2> actions +) { + public static ActionsResponse of(List<ActionAppResponse> actions) { + return new ActionsResponse(actions.stream() + .map(ActionResponse2::of) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java new file mode 100644 index 000000000..10f71b82e --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.BillActionDetailAppResponse; + +public record BillActionDetailResponse( + String name, + Long price, + boolean isFixed +) { + + public static BillActionDetailResponse of(BillActionDetailAppResponse billActionDetailAppResponse) { + return new BillActionDetailResponse( + billActionDetailAppResponse.name(), + billActionDetailAppResponse.price(), + billActionDetailAppResponse.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java new file mode 100644 index 000000000..182e76db6 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.application.response.BillActionDetailsAppResponse; + +public record BillActionDetailsResponse( + List<BillActionDetailResponse> members +) { + + public static BillActionDetailsResponse of(BillActionDetailsAppResponse billActionDetailsAppResponse) { + return billActionDetailsAppResponse.billActionDetailAppResponses().stream() + .map(BillActionDetailResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsResponse::new)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java new file mode 100644 index 000000000..289cca4fa --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.CurrentMemberAppResponse; + +public record CurrentMembersResponse(List<String> memberNames) { + + public static CurrentMembersResponse of(List<CurrentMemberAppResponse> currentMembers) { + List<String> responses = currentMembers.stream() + .map(CurrentMemberAppResponse::name) + .toList(); + + return new CurrentMembersResponse(responses); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java new file mode 100644 index 000000000..c18694393 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.EventDetailAppResponse; + +public record EventDetailResponse(String eventName) { + + public static EventDetailResponse of(EventDetailAppResponse response) { + return new EventDetailResponse(response.eventName()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventResponse.java new file mode 100644 index 000000000..506f5e814 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/EventResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.EventAppResponse; + +public record EventResponse(String eventId) { + + public static EventResponse of(EventAppResponse eventAppResponse) { + return new EventResponse(eventAppResponse.token()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java new file mode 100644 index 000000000..0ea409202 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.MemberBillReportAppResponse; + +public record MemberBillReportResponse(String name, Long price) { + + public static MemberBillReportResponse of(MemberBillReportAppResponse memberBillReportAppResponse) { + return new MemberBillReportResponse(memberBillReportAppResponse.name(), memberBillReportAppResponse.price()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java new file mode 100644 index 000000000..d350c4009 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.MemberBillReportAppResponse; + +public record MemberBillReportsResponse(List<MemberBillReportResponse> reports) { + + public static MemberBillReportsResponse of(List<MemberBillReportAppResponse> memberBillReports) { + List<MemberBillReportResponse> reports = memberBillReports.stream() + .map(MemberBillReportResponse::of) + .toList(); + + return new MemberBillReportsResponse(reports); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java new file mode 100644 index 000000000..0947d9e02 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java @@ -0,0 +1,13 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.MembersAppResponse; + +public record MembersResponse( + List<String> memberNames +) { + + public static MembersResponse of(MembersAppResponse response) { + return new MembersResponse(response.memberNames()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java new file mode 100644 index 000000000..55dd62c58 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -0,0 +1,27 @@ +package server.haengdong.presentation.response; + +import java.util.ArrayList; +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; + +public record StepResponse( + String stepName, + String type, + List<String> members, + List<ActionResponse> actions +) { + public static StepResponse of(String stepName, List<String> members, List<ActionAppResponse> actions) { + return new StepResponse( + stepName, + actions.get(0).actionTypeName(), + new ArrayList<>(members), + toActionsResponse(actions) + ); + } + + private static List<ActionResponse> toActionsResponse(List<ActionAppResponse> actions) { + return actions.stream() + .map(ActionResponse::of) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java new file mode 100644 index 000000000..5f7573d67 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java @@ -0,0 +1,56 @@ +package server.haengdong.presentation.response; + +import java.util.ArrayList; +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; + +public record StepsResponse(List<StepResponse> steps) { + + public static StepsResponse of(List<ActionAppResponse> actions) { + List<StepResponse> steps = new ArrayList<>(); + List<String> currentMembers = new ArrayList<>(); + List<List<ActionAppResponse>> groups = createGroups(actions); + + int billStepCount = 0; + for (List<ActionAppResponse> group : groups) { + changeCurrentMembers(group, currentMembers); + if (group.get(0).actionType() == ActionType.BILL) { + billStepCount++; + } + StepResponse stepResponse = StepResponse.of(billStepCount + "์ฐจ", currentMembers, group); + steps.add(stepResponse); + } + return new StepsResponse(steps); + } + + private static List<List<ActionAppResponse>> createGroups(List<ActionAppResponse> actions) { + List<List<ActionAppResponse>> groups = new ArrayList<>(); + + for (ActionAppResponse action : actions) { + if (groups.isEmpty() || isActionTypeChange(action, groups)) { + groups.add(new ArrayList<>()); + } + groups.get(groups.size() - 1).add(action); + } + + return groups; + } + + private static boolean isActionTypeChange(ActionAppResponse action, List<List<ActionAppResponse>> groups) { + List<ActionAppResponse> currentGroup = groups.get(groups.size() - 1); + return currentGroup.get(0).actionType() != action.actionType(); + } + + private static void changeCurrentMembers(List<ActionAppResponse> group, List<String> currentMembers) { + for (ActionAppResponse action : group) { + if (action.actionType() == ActionType.IN) { + currentMembers.add(action.name()); + continue; + } + if (action.actionType() == ActionType.OUT) { + currentMembers.remove(action.name()); + } + } + } +} diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml new file mode 100644 index 000000000..2ae503547 --- /dev/null +++ b/server/src/main/resources/application.yml @@ -0,0 +1,66 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:database + username: sa + password: + + h2: + console: + enabled: true + path: /h2-console + + jpa: + hibernate: + ddl-auto: create + properties: + hibernate: + format_sql: true + jdbc.time_zone: Asia/Seoul + show-sql: true + +cors: + max-age: 3600 + allowed-origins: http://localhost:3000, https://haengdong.pro, https://dev.haengdong.pro, https://app.haengdong.pro + +security: + jwt: + token: + secret-key: skdmeejEKJdkDjklDlkj123DKLJ3kDkeDkDKQMEOD1D90D8dE + expire-length: 604800000 # 1์ฃผ์ผ + +cookie: + http-only: false + secure: false + path: / + same-site: none + max-age: 7D + +management: + endpoints: + web: + exposure: + include: health, metrics, logfile + +server: + servlet: + encoding: + charset: UTF-8 + enabled: true + force: true + +--- + +spring: + config: + import: classpath:config/application-prod.yml + activate: + on-profile: prod + +--- + +spring: + config: + import: classpath:config/application-dev.yml + activate: + on-profile: dev diff --git a/server/src/main/resources/config b/server/src/main/resources/config new file mode 160000 index 000000000..fa4270674 --- /dev/null +++ b/server/src/main/resources/config @@ -0,0 +1 @@ +Subproject commit fa42706743e6eb3f4fd8c34618614eff8ae94b3d diff --git a/server/src/main/resources/logback-spring.xml b/server/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..283b966a3 --- /dev/null +++ b/server/src/main/resources/logback-spring.xml @@ -0,0 +1,97 @@ +<configuration> + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <!-- ์ฝ˜์†”์— ๋กœ๊ทธ ์ถœ๋ ฅ ํ˜•์‹ --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="ERROR-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>ERROR</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-error.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-error.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- ๋‚ ์งœ, ์‹œ๊ฐ„, ๋กœ๊ทธ ๋ ˆ๋ฒจ, ์Šค๋ ˆ๋“œ ์ด๋ฆ„, ๋กœ๊ฑฐ ์ด๋ฆ„, ๋ฉ”์‹œ์ง€ ํ˜•์‹ --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="WARN-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>WARN</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-warn.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-warn.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- ๋‚ ์งœ, ์‹œ๊ฐ„, ๋กœ๊ทธ ๋ ˆ๋ฒจ, ์Šค๋ ˆ๋“œ ์ด๋ฆ„, ๋กœ๊ฑฐ ์ด๋ฆ„, ๋ฉ”์‹œ์ง€ ํ˜•์‹ --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="INFO-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>INFO</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-info.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-info.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- ๋‚ ์งœ, ์‹œ๊ฐ„, ๋กœ๊ทธ ๋ ˆ๋ฒจ, ์Šค๋ ˆ๋“œ ์ด๋ฆ„, ๋กœ๊ฑฐ ์ด๋ฆ„, ๋ฉ”์‹œ์ง€ ํ˜•์‹ --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="DEBUG-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>DEBUG</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-debug.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-debug.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- ๋‚ ์งœ, ์‹œ๊ฐ„, ๋กœ๊ทธ ๋ ˆ๋ฒจ, ์Šค๋ ˆ๋“œ ์ด๋ฆ„, ๋กœ๊ฑฐ ์ด๋ฆ„, ๋ฉ”์‹œ์ง€ ํ˜•์‹ --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <springProfile name="default"> + <root level="INFO"> + <appender-ref ref="CONSOLE"/> + </root> + </springProfile> + + <springProfile name="dev"> + <root level="INFO"> + <appender-ref ref="ERROR-ROLLING"/> + <appender-ref ref="WARN-ROLLING"/> + <appender-ref ref="INFO-ROLLING"/> + <appender-ref ref="DEBUG-ROLLING"/> + </root> + </springProfile> + + <springProfile name="prod"> + <root level="ERROR"> + <appender-ref ref="ERROR-ROLLING"/> + </root> + </springProfile> +</configuration> diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java new file mode 100644 index 000000000..ee979b278 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -0,0 +1,91 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class ActionServiceTest extends ServiceTestSupport { + + @Autowired + private ActionService actionService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @DisplayName("์ฐธ์—ฌ์ž๋ณ„ ์ •์‚ฐ ํ˜„ํ™ฉ์„ ์กฐํšŒํ•œ๋‹ค.") + @Test + void getMemberBillReports() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(savedEvent, 1L), "์†Œํ•˜", IN, 1L), + new MemberAction(new Action(savedEvent, 2L), "๊ฐ์ž", IN, 1L), + new MemberAction(new Action(savedEvent, 3L), "์ฟ ํ‚ค", IN, 1L), + new MemberAction(new Action(savedEvent, 5L), "๊ฐ์ž", OUT, 2L) + ); + List<BillAction> billActions = List.of( + new BillAction(new Action(savedEvent, 4L), "๋ฝ•์กฑ", 60_000L), + new BillAction(new Action(savedEvent, 7L), "์ธ์ƒ๋„ค์ปท", 20_000L) + ); + billActions.get(0).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "์†Œํ•˜", 10_000L, false), + new BillActionDetail(BILL_ACTION, "๊ฐ์ž", 40_000L, true), + new BillActionDetail(BILL_ACTION, "์ฟ ํ‚ค", 10_000L, false) + ) + ); + billActions.get(1).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "์†Œํ•˜", 5_000L, true), + new BillActionDetail(BILL_ACTION, "์ฟ ํ‚ค", 15_000L, true) + ) + ); + memberActionRepository.saveAll(memberActions); + billActionRepository.saveAll(billActions); + + List<MemberBillReportAppResponse> responses = actionService.getMemberBillReports(event.getToken()); + + assertThat(responses) + .hasSize(3) + .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) + .containsExactlyInAnyOrder( + tuple("๊ฐ์ž", 40_000L), + tuple("์ฟ ํ‚ค", 25_000L), + tuple("์†Œํ•˜", 15_000L) + ); + } + + @DisplayName("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ด๋ฒคํŠธ์˜ ์ฐธ์—ฌ์ž๋ณ„ ์ •์‚ฐ ํ˜„ํ™ฉ์„ ์กฐํšŒํ•˜๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.") + @Test + void getMemberBillReports1() { + assertThatThrownBy(() -> actionService.getMemberBillReports("invalid token")) + .isInstanceOf(HaengdongException.class) + .hasMessage(HaengdongErrorCode.EVENT_NOT_FOUND.getMessage()); + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java new file mode 100644 index 000000000..7074ce846 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java @@ -0,0 +1,111 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class BillActionDetailServiceTest extends ServiceTestSupport { + + @Autowired + private BillActionDetailService billActionDetailService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + + @DisplayName("์ฐธ์—ฌ์ž๋ณ„ ์ง€์ถœ ๊ธˆ์•ก์„ ์กฐํšŒํ•œ๋‹ค.") + @Test + void findBillActionDetailsTest() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "๋ฝ•์กฑ", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "ํ† ๋‹ค๋ฆฌ", 6000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "์ฟ ํ‚ค", 4000L, true); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsAppResponse response = billActionDetailService.findBillActionDetails( + event1.getToken(), action.getId()); + + assertThat(response.billActionDetailAppResponses()).hasSize(2) + .extracting(BillActionDetailAppResponse::name, BillActionDetailAppResponse::price) + .containsExactly( + tuple("ํ† ๋‹ค๋ฆฌ", 6000L), + tuple("์ฟ ํ‚ค", 4000L) + ); + } + + @DisplayName("์ง€์ถœ ๊ธˆ์•ก ์ˆ˜์ • ์š”์ฒญ์˜ ์ดํ•ฉ์ด ์ง€์ถœ ๊ธˆ์•ก๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.") + @Test + void updateBillActionDetailsTest1() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "๋ฝ•์กฑ", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "ํ† ๋‹ค๋ฆฌ", 5000L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "์ฟ ํ‚ค", 5000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( + new BillActionDetailUpdateAppRequest("ํ† ๋‹ค๋ฆฌ", 3000L, true), + new BillActionDetailUpdateAppRequest("์ฟ ํ‚ค", 4000L, true) + )); + assertThatCode( + () -> billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request)) + .isInstanceOf(HaengdongException.class) + .hasMessage("์ง€์ถœ ์ด์•ก์ด ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + + @DisplayName("์ง€์ถœ ๊ณ ์ • ๊ธˆ์•ก์„ ์ˆ˜์ •ํ•œ๋‹ค.") + @Test + void updateBillActionDetailsTest2() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "๋ฝ•์กฑ", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "ํ† ๋‹ค๋ฆฌ", 5000L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "์ฟ ํ‚ค", 5000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( + new BillActionDetailUpdateAppRequest("ํ† ๋‹ค๋ฆฌ", 3000L, true), + new BillActionDetailUpdateAppRequest("์ฟ ํ‚ค", 7000L, true) + )); + billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request); + + List<BillActionDetail> results = billActionDetailRepository.findAll(); + + assertThat(results).hasSize(2) + .extracting(BillActionDetail::getMemberName, BillActionDetail::getPrice) + .containsExactly( + tuple("ํ† ๋‹ค๋ฆฌ", 3000L), + tuple("์ฟ ํ‚ค", 7000L) + ); + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java new file mode 100644 index 000000000..39e52f80c --- /dev/null +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -0,0 +1,229 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.application.request.BillActionUpdateAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class BillActionServiceTest extends ServiceTestSupport { + + @Autowired + private BillActionService billActionService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ์„ ์ƒ์„ฑํ•œ๋‹ค.") + @Test + void saveAllBillAction() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "๋ฐฑํ˜ธ", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "๋ง์ตธ", MemberActionStatus.IN, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + List<BillActionAppRequest> requests = List.of( + new BillActionAppRequest("๋ฝ•์กฑ", 10_000L), + new BillActionAppRequest("์ธ์ƒ๋งฅ์ฃผ", 15_000L) + ); + + billActionService.saveAllBillAction(event.getToken(), requests); + + List<BillAction> actions = billActionRepository.findByAction_Event(savedEvent); + + assertThat(actions).extracting(BillAction::getTitle, BillAction::getPrice, BillAction::getSequence) + .containsExactlyInAnyOrder( + tuple("๋ฝ•์กฑ", 10_000L, 3L), + tuple("์ธ์ƒ๋งฅ์ฃผ", 15_000L, 4L) + ); + } + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ์„ ์ƒ์„ฑํ•˜๋ฉด ์ง€์ถœ ์ƒ์„ธ ๋‚ด์—ญ์ด ์ƒ์„ฑ๋œ๋‹ค.") + @Test + void saveAllBillActionTest1() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "๋ฐฑํ˜ธ", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "๋ง์ตธ", MemberActionStatus.IN, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + List<BillActionAppRequest> request = List.of( + new BillActionAppRequest("๋ฝ•์กฑ", 10_000L), + new BillActionAppRequest("์ธ์ƒ๋งฅ์ฃผ", 15_000L) + ); + + billActionService.saveAllBillAction(event.getToken(), request); + + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAll(); + + assertThat(billActionDetails) + .hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("๋ฐฑํ˜ธ", 5_000L), + tuple("๋ง์ตธ", 5_000L), + tuple("๋ฐฑํ˜ธ", 7_500L), + tuple("๋ง์ตธ", 7_500L) + ); + } + + @DisplayName("์ด๋ฒคํŠธ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ง€์ถœ ๋‚ด์—ญ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void saveAllBillAction1() { + List<BillActionAppRequest> requests = List.of( + new BillActionAppRequest("๋ฝ•์กฑ", 10_000L), + new BillActionAppRequest("์ธ์ƒ๋งฅ์ฃผ", 15_000L) + ); + + assertThatThrownBy(() -> billActionService.saveAllBillAction("token", requests)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("์ง€์ถœ ์•ก์…˜์„ ์ˆ˜์ •ํ•œ๋‹ค.") + @Test + void updateBillAction() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action = Action.createFirst(savedEvent); + BillAction billAction = new BillAction(action, "๋ฝ•์กฑ", 10_000L); + BillAction savedBillAction = billActionRepository.save(billAction); + + Long actionId = savedBillAction.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("์ธ์ƒ๋งฅ์ฃผ", 20_000L); + + billActionService.updateBillAction(event.getToken(), actionId, request); + + BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); + + assertAll( + () -> assertThat(updatedBillAction.getTitle()).isEqualTo("์ธ์ƒ๋งฅ์ฃผ"), + () -> assertThat(updatedBillAction.getPrice()).isEqualTo(20_000L) + ); + } + + @DisplayName("ํ–‰์‚ฌ์— ์†ํ•˜์ง€ ์•Š์€ ์ง€์ถœ ์•ก์…˜์€ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void updateBillAction1() { + Event event1 = Fixture.EVENT1; + Event event2 = Fixture.EVENT2; + Event savedEvent1 = eventRepository.save(event1); + Event savedEvent2 = eventRepository.save(event2); + Action action1 = Action.createFirst(savedEvent1); + Action action2 = Action.createFirst(savedEvent2); + BillAction billAction1 = new BillAction(action1, "๋ฝ•์กฑ", 10_000L); + BillAction billAction2 = new BillAction(action2, "๋ฝ•์กฑ", 10_000L); + BillAction savedBillAction1 = billActionRepository.save(billAction1); + billActionRepository.save(billAction2); + + Long actionId = savedBillAction1.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("์ธ์ƒ๋งฅ์ฃผ", 20_000L); + + assertThatThrownBy(() -> billActionService.updateBillAction(event2.getToken(), actionId, request)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ ๊ธˆ์•ก์„ ๋ณ€๊ฒฝํ•˜๋ฉด ์ง€์ถœ ๋””ํ…Œ์ผ์ด ์ดˆ๊ธฐํ™” ๋œ๋‹ค.") + @Test + void updateBillAction2() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action = Action.createFirst(savedEvent); + BillAction billAction = new BillAction(action, "๋ฝ•์กฑ", 10_000L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "๊ฐ์ž", 3000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "๊ณ ๊ตฌ๋งˆ", 2000L, true); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "๋‹น๊ทผ", 3000L, true); + BillActionDetail billActionDetail4 = new BillActionDetail(billAction, "์–‘ํŒŒ", 2000L, true); + billAction.addDetails(List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); + BillAction savedBillAction = billActionRepository.save(billAction); + + Long actionId = savedBillAction.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("์ธ์ƒ๋งฅ์ฃผ", 20_000L); + + billActionService.updateBillAction(event.getToken(), actionId, request); + + BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(updatedBillAction); + + assertThat(billActionDetails).hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("๊ฐ์ž", 5000L), + tuple("๊ณ ๊ตฌ๋งˆ", 5000L), + tuple("๋‹น๊ทผ", 5000L), + tuple("์–‘ํŒŒ", 5000L) + ); + } + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ์„ ์‚ญ์ œํ•œ๋‹ค.") + @Test + void deleteBillAction() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + BillAction billAction = new BillAction(new Action(event, 1L), "์ปคํ”ผ", 50_900L); + billActionRepository.save(billAction); + Long actionId = billAction.getAction().getId(); + + billActionService.deleteBillAction(event.getToken(), actionId); + + assertThat(billActionRepository.findById(billAction.getId())).isEmpty(); + } + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ์„ ์‚ญ์ œํ•˜๋ฉด ์ง€์ถœ ์ƒ์„ธ๋„ ์‚ญ์ œ๋œ๋‹ค.") + @Test + void deleteBillActionTest1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "๋ฐฑํ˜ธ", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "๋ง์ตธ", MemberActionStatus.IN, 2L); + BillAction billAction = new BillAction(new Action(event, 3L), "์ปคํ”ผ", 50_900L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "๋ฐฑํ˜ธ", 25_450L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "๋ง์ตธ", 25_450L, false); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + billActionRepository.save(billAction); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + Long actionId = billAction.getAction().getId(); + + billActionService.deleteBillAction(event.getToken(), actionId); + + assertThat(billActionDetailRepository.findAll()).isEmpty(); + } + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ ์‚ญ์ œ ์‹œ ํ–‰์‚ฌ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.") + @Test + void deleteBillAction1() { + assertThatThrownBy(() -> billActionService.deleteBillAction("์†Œํ•˜๋ง์ตธ", 1L)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java new file mode 100644 index 000000000..407fa1457 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -0,0 +1,231 @@ +package server.haengdong.application; + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.BDDMockito.given; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.MemberNameUpdateAppRequest; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class EventServiceTest extends ServiceTestSupport { + + @Autowired + private EventService eventService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @MockBean + private EventTokenProvider eventTokenProvider; + + @DisplayName("ํ–‰์‚ฌ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค") + @Test + void saveEventTest() { + EventAppRequest request = new EventAppRequest("test", "1234"); + given(eventTokenProvider.createToken()).willReturn("TOKEN"); + + EventAppResponse response = eventService.saveEvent(request); + + assertThat(response.token()).isEqualTo("TOKEN"); + } + + @DisplayName("ํ† ํฐ์œผ๋กœ ํ–‰์‚ฌ๋ฅผ ์กฐํšŒํ•œ๋‹ค.") + @Test + void findEventTest() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + + EventDetailAppResponse eventDetailAppResponse = eventService.findEvent(event.getToken()); + + assertThat(eventDetailAppResponse.eventName()).isEqualTo(event.getName()); + } + + @DisplayName("ํ–‰์‚ฌ์— ์†ํ•œ ๋ชจ๋“  ์•ก์…˜์„ ์กฐํšŒํ•œ๋‹ค.") + @Test + void findActionsTest() { + Event event = Fixture.EVENT1; + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "ํ† ๋‹ค๋ฆฌ", IN, 1L); + Action action1 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "์ฟ ํ‚ค", IN, 1L); + Action action2 = new Action(event, 3L); + BillAction billAction = new BillAction(action2, "๋ฝ•๋‚˜๋ฌด์Ÿ์ด์กฑ๋ฐœ", 30000L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction, memberAction1)); + billActionRepository.save(billAction); + + List<ActionAppResponse> actionAppResponses = eventService.findActions(event.getToken()); + + assertThat(actionAppResponses).hasSize(3) + .extracting(ActionAppResponse::actionId, + ActionAppResponse::name, + ActionAppResponse::price, + ActionAppResponse::sequence, + ActionAppResponse::actionTypeName) + .containsExactly( + tuple(1L, "ํ† ๋‹ค๋ฆฌ", null, 1L, "IN"), + tuple(2L, "์ฟ ํ‚ค", null, 2L, "IN"), + tuple(3L, "๋ฝ•๋‚˜๋ฌด์Ÿ์ด์กฑ๋ฐœ", 30000L, 3L, "BILL") + ); + } + + @DisplayName("ํ–‰์‚ฌ์— ์ฐธ์—ฌํ•œ ์ „์ฒด ์ธ์›์„ ์ค‘๋ณต ์—†์ด ์กฐํšŒํ•œ๋‹ค.") + @Test + void findAllMembersTest() { + Event event = Fixture.EVENT1; + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + Action action3 = new Action(event, 3L); + Action action4 = new Action(event, 4L); + BillAction billAction = new BillAction(action3, "๋ฝ•๋‚˜๋ฌด์Ÿ์ด์กฑ๋ฐœ", 30000L); + MemberAction memberAction1 = new MemberAction(action1, "ํ† ๋‹ค๋ฆฌ", IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "์ฟ ํ‚ค", IN, 1L); + MemberAction memberAction3 = new MemberAction(action4, "์ฟ ํ‚ค", OUT, 1L); + eventRepository.save(event); + billActionRepository.save(billAction); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MembersAppResponse membersAppResponse = eventService.findAllMembers(event.getToken()); + + assertThat(membersAppResponse.memberNames()).containsExactlyInAnyOrder("ํ† ๋‹ค๋ฆฌ", "์ฟ ํ‚ค"); + } + + @DisplayName("ํ–‰์‚ฌ ์ฐธ์—ฌ ์ธ์›๋“ค์˜ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•œ๋‹ค.") + @Test + void updateMember() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "ํ† ๋‹ค๋ฆฌ", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "์ฟ ํ‚ค", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "์›จ๋””", IN, 2L); + MemberAction memberAction4 = new MemberAction(new Action(event, 4L), "์ฟ ํ‚ค", OUT, 3L); + MemberAction memberAction5 = new MemberAction(new Action(event, 5L), "์ฟ ํ‚ค", IN, 4L); + MemberAction memberAction6 = new MemberAction(new Action(event, 6L), "์ฟ ํ‚ค", OUT, 5L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of( + memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6 + )); + + eventService.updateMember(event.getToken(), new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("์ฟ ํ‚ค", "์ฟก์ฟก"), + new MemberNameUpdateAppRequest("ํ† ๋‹ค๋ฆฌ", "ํ† ์Ÿ์ด") + ))); + + List<MemberAction> foundMemberActions = memberActionRepository.findAllByEvent(event); + assertThat(foundMemberActions) + .extracting(MemberAction::getId, MemberAction::getMemberName) + .contains( + tuple(memberAction1.getId(), "ํ† ์Ÿ์ด"), + tuple(memberAction2.getId(), "์ฟก์ฟก"), + tuple(memberAction3.getId(), "์›จ๋””"), + tuple(memberAction4.getId(), "์ฟก์ฟก"), + tuple(memberAction5.getId(), "์ฟก์ฟก"), + tuple(memberAction6.getId(), "์ฟก์ฟก") + ); + } + + @DisplayName("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์ธ์›์˜ ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void updateMember1() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "ํ† ๋‹ค๋ฆฌ", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "์ฟ ํ‚ค", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "์›จ๋””", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("์ฟ ํ‚ค", "์ฟก์ฟก"), + new MemberNameUpdateAppRequest("์›จ๋””", "ํ† ๋‹ค๋ฆฌ") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ธ์›์€ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void updateMember2() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "ํ† ๋‹ค๋ฆฌ", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "์ฟ ํ‚ค", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "์›จ๋””", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("์ฟก์ฟก", "ํ† ์Ÿ์ด"), + new MemberNameUpdateAppRequest("์›จ๋””", "๋ง๋ณต") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("๋ณ€๊ฒฝ ์ „ ์ฐธ์—ฌ ์ธ์› ์ด๋ฆ„์ด ์ค‘๋ณต๋  ์ˆ˜ ์—†๋‹ค.") + @Test + void updateMember3() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "ํ† ๋‹ค๋ฆฌ", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "์ฟ ํ‚ค", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "์›จ๋””", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("์ฟ ํ‚ค", "์ฟก์ฟก"), + new MemberNameUpdateAppRequest("์ฟ ํ‚ค", "ํ† ์Ÿ์ด") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("๋ณ€๊ฒฝ ํ›„ ์ฐธ์—ฌ ์ธ์› ์ด๋ฆ„์ด ์ค‘๋ณต๋  ์ˆ˜ ์—†๋‹ค.") + @Test + void updateMember4() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "ํ† ๋‹ค๋ฆฌ", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "์ฟ ํ‚ค", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "์›จ๋””", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("์ฟ ํ‚ค", "์ฟก์ฟก"), + new MemberNameUpdateAppRequest("ํ† ๋‹ค๋ฆฌ", "์ฟก์ฟก") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java new file mode 100644 index 000000000..c04f06026 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -0,0 +1,223 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class MemberActionFactoryTest extends ServiceTestSupport { + + @Autowired + private MemberActionFactory memberActionFactory; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private EventRepository eventRepository; + + @DisplayName("์ด์ „ ๋ฉค๋ฒ„ ์•ก์…˜์ด ์‹œํ€€์Šค ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ์ƒˆ๋กœ์šด ๋ฉค๋ฒ„ ์•ก์…˜ ์š”์ฒญ์„ ๊ฒ€์ฆํ•œ๋‹ค.") + @Test + void createMemberActionsTest() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "ํ† ๋‹ค๋ฆฌ", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "ํ† ๋‹ค๋ฆฌ", MemberActionStatus.OUT, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("ํ† ๋‹ค๋ฆฌ", "OUT"))); + + List<MemberAction> unorderedMemberActions = List.of(memberAction2, memberAction1); + CurrentMembers currentMembers = CurrentMembers.of(unorderedMemberActions); + Action startAction = new Action(event, 3L); + + assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("์ธ์› ๋ณ€๋™ ์•ก์…˜์„ ์ƒ์„ฑํ•œ๋‹ค.") + @Test + void createMemberActionsTest1() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "ํ† ๋‹ค๋ฆฌ", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("ํ† ๋‹ค๋ฆฌ", "OUT"))); + Action startAction = new Action(event, 2L); + + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + List<MemberAction> memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, + currentMembers, startAction + ); + + assertThat(memberActions).hasSize(1) + .extracting(MemberAction::getAction, MemberAction::getMemberName, MemberAction::getStatus) + .containsExactly( + tuple(startAction, "ํ† ๋‹ค๋ฆฌ", MemberActionStatus.OUT) + ); + } + + @DisplayName("ํ˜„์žฌ ํ–‰์‚ฌ์— ์ฐธ์—ฌ ์ค‘์ธ ๊ฒฝ์šฐ์— ํ‡ด์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.") + @Test + void createMemberActionsTest2() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "ํ† ๋‹ค๋ฆฌ", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("ํ† ๋‹ค๋ฆฌ", "OUT"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("ํ–‰์‚ฌ์—์„œ ํ‡ด์žฅํ•œ ๊ฒฝ์šฐ์— ์ž…์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.") + @Test + void createMemberActionsTest3() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action1 = new Action(event, 1L); + MemberAction memberAction1 = new MemberAction(action1, "ํ† ๋‹ค๋ฆฌ", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction1); + Action action2 = new Action(event, 2L); + MemberAction memberAction2 = new MemberAction(action2, "ํ† ๋‹ค๋ฆฌ", MemberActionStatus.OUT, 2L); + memberActionRepository.save(memberAction2); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("ํ† ๋‹ค๋ฆฌ", "IN"))); + Action startAction = new Action(event, 3L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction1, memberAction2)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("ํ–‰์‚ฌ์— ์ž…์žฅํ•œ ์  ์—†๋Š” ๊ฒฝ์šฐ์— ์ž…์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.") + @Test + void createMemberActionsTest4() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "ํ† ๋‹ค๋ฆฌ", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("์ฟ ํ‚ค", "IN"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("ํ–‰์‚ฌ์— ์ž…์žฅํ•˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ ํ‡ด์žฅํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void createMemberActionTest5() { + Event event = eventRepository.save(Fixture.EVENT1); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("์ฟ ํ‚ค", "OUT"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of()); + + assertThatCode( + () -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("ํ–‰์‚ฌ์— ์ด๋ฏธ ์ฐธ์—ฌ ์ค‘์ธ ๊ฒฝ์šฐ ๋‹ค์‹œ ์ž…์žฅํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void createMemberActionTest6() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "์ฟ ํ‚ค", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("์ฟ ํ‚ค", "IN"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("ํ•œ ๋ช…์˜ ์‚ฌ์šฉ์ž๋Š” ๋™์‹œ์— ์—ฌ๋Ÿฌ ๋ฒˆ ์ž…์žฅํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void createMemberActionTest7() { + Event event = eventRepository.save(Fixture.EVENT1); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of( + new MemberActionSaveAppRequest("์ฟ ํ‚ค", "IN"), + new MemberActionSaveAppRequest("์ฟ ํ‚ค", "IN") + )); + Action startAction = new Action(event, 1L); + CurrentMembers currentMembers = CurrentMembers.of(List.of()); + + assertThatCode( + () -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("ํ•œ ๋ช…์˜ ์‚ฌ์šฉ์ž๋Š” ๋™์‹œ์— ์—ฌ๋Ÿฌ ๋ฒˆ ํ‡ด์žฅํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void createMemberActionTest8() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "์ฟ ํ‚ค", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of( + new MemberActionSaveAppRequest("์ฟ ํ‚ค", "OUT"), + new MemberActionSaveAppRequest("์ฟ ํ‚ค", "OUT") + )); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("ํ•œ ๋ช…์˜ ์‚ฌ์šฉ์ž๋Š” ์ž…์žฅ๊ณผ ํ‡ด์žฅ์„ ๋™์‹œ์— ํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void createMemberActionTest9() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "์ฟ ํ‚ค", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of( + new MemberActionSaveAppRequest("์ฟ ํ‚ค", "IN"), + new MemberActionSaveAppRequest("์ฟ ํ‚ค", "OUT") + )); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java new file mode 100644 index 000000000..b6d29444c --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -0,0 +1,251 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.groups.Tuple.tuple; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class MemberActionServiceTest extends ServiceTestSupport { + + @Autowired + private MemberActionService memberActionService; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + + @DisplayName("ํ˜„์žฌ ํ–‰์‚ฌ์— ์ฐธ์—ฌํ•˜๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ์— ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.") + @Test + void saveMemberActionTest() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "๋ง์ตธ", IN, 1L); + memberActionRepository.save(memberAction); + + assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("๋ง์ตธ", "OUT"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("ํ–‰์‚ฌ์—์„œ ํ‡ด์žฅํ•œ ๊ฒฝ์šฐ์— ์ž…์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.") + @Test + void saveMemberActionTest1() { + Event event = eventRepository.save(Fixture.EVENT1); + Action actionOne = new Action(event, 1L); + MemberAction memberActionOne = new MemberAction(actionOne, "๋ง์ตธ", IN, 1L); + memberActionRepository.save(memberActionOne); + + Action actionTwo = new Action(event, 2L); + MemberAction memberActionTwo = new MemberAction(actionTwo, "๋ง์ตธ", OUT, 1L); + memberActionRepository.save(memberActionTwo); + + assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("๋ง์ตธ", "IN"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("ํ–‰์‚ฌ์— ์ž…์žฅํ•˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ ํ‡ด์žฅํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void saveMemberActionTest2() { + MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("์ด๋ฒคํŠธ๊ฐ€ ์—†์œผ๋ฉด ํ˜„์žฌ ์ฐธ์—ฌ ์ธ์›์„ ์กฐํšŒํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void getCurrentMembers() { + assertThatThrownBy(() -> memberActionService.getCurrentMembers("token")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("ํ–‰์‚ฌ์˜ ์ „์ฒด ์ฐธ์—ฌ์ž ์ค‘์—์„œ ํŠน์ • ์ฐธ์—ฌ์ž์˜ ๋งด๋ฒ„ ์•ก์…˜์„ ์ „๋ถ€ ์‚ญ์ œํ•œ๋‹ค.") + @Test + void deleteMember() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "์ฐธ์—ฌ์ž", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "ํ† ๋‹ค๋ฆฌ", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "์ฟ ํ‚ค", IN, 1L); + MemberAction memberAction4 = new MemberAction(new Action(event, 4L), "์†Œํ•˜", IN, 1L); + MemberAction memberAction5 = new MemberAction(new Action(event, 5L), "์›จ๋””", IN, 1L); + MemberAction memberAction6 = new MemberAction(new Action(event, 6L), "์ฐธ์—ฌ์ž", OUT, 1L); + memberActionRepository.saveAll( + List.of(memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6)); + + Event event2 = Fixture.EVENT2; + eventRepository.save(event2); + Action action2 = Action.createFirst(event2); + MemberAction anotherMemberAction = new MemberAction(action2, "์ฐธ์—ฌ์ž", IN, 1L); + memberActionRepository.save(anotherMemberAction); + + memberActionService.deleteMember(event.getToken(), "์ฐธ์—ฌ์ž"); + + List<MemberAction> memberActions = memberActionRepository.findAll(); + + assertThat(memberActions).hasSize(5) + .extracting("memberName", "status") + .containsExactly( + tuple("ํ† ๋‹ค๋ฆฌ", IN), + tuple("์ฟ ํ‚ค", IN), + tuple("์†Œํ•˜", IN), + tuple("์›จ๋””", IN), + tuple("์ฐธ์—ฌ์ž", IN) + ); + } + + @DisplayName("์ด๋ฒคํŠธ์— ์†ํ•œ ๋ฉค๋ฒ„์„ ์‚ญ์ œํ•˜๋ฉด ์ „์ฒด ์ง€์ถœ ๋‚ด์—ญ ๋””ํ…Œ์ผ์ด ์ดˆ๊ธฐํ™”๋œ๋‹ค.") + @Test + void deleteMember1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "ํ† ๋‹ค๋ฆฌ", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "ํ† ๋‹ค๋ฆฌ", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "์ฟ ํ‚ค", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "์›จ๋””", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "๊ฐ์ž", IN, 5L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5 + ) + ); + BillAction billAction = new BillAction(new Action(event, 6L), "๋ฝ•์กฑ", 100_000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "์ฟ ํ‚ค", 40_000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "์›จ๋””", 30_000L, false); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "๊ฐ์ž", 30_000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); + List<BillActionDetail> allByBillAction = billActionDetailRepository.findAllByBillAction(billAction); + System.out.println("allByBillAction = " + allByBillAction.isEmpty()); + + memberActionService.deleteMember(event.getToken(), "์ฟ ํ‚ค"); + + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); + + assertThat(billActionDetails).hasSize(2) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("์›จ๋””", 50_000L), + tuple("๊ฐ์ž", 50_000L) + ); + } + + @DisplayName("์ด๋ฒคํŠธ์— ์†ํ•œ ๋ฉค๋ฒ„ ์•ก์…˜์„ ์‚ญ์ œํ•˜๋ฉด ์ดํ›„์— ๊ธฐ๋ก๋œ ํ•ด๋‹น ์ฐธ์—ฌ์ž์˜ ๋ชจ๋“  ๋ฉค๋ฒ„ ์•ก์…˜์„ ์‚ญ์ œํ•œ๋‹ค.") + @Test + void deleteMemberAction() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "ํ† ๋‹ค๋ฆฌ", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "ํ† ๋‹ค๋ฆฌ", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "์ฟ ํ‚ค", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "์›จ๋””", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "ํ† ๋‹ค๋ฆฌ", IN, 5L); + MemberAction memberAction6 = createMemberAction(new Action(event, 6L), "ํ† ๋‹ค๋ฆฌ", OUT, 6L); + MemberAction memberAction7 = createMemberAction(new Action(event, 7L), "์ฟ ํ‚ค", OUT, 7L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5, + memberAction6, + memberAction7) + ); + + memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); + List<MemberAction> memberActions = memberActionRepository.findAll(); + + assertThat(memberActions).hasSize(4) + .extracting("id", "memberName", "status") + .containsExactly( + tuple(memberAction1.getId(), "ํ† ๋‹ค๋ฆฌ", IN), + tuple(memberAction3.getId(), "์ฟ ํ‚ค", IN), + tuple(memberAction4.getId(), "์›จ๋””", IN), + tuple(memberAction7.getId(), "์ฟ ํ‚ค", OUT) + ); + } + + @DisplayName("์ด๋ฒคํŠธ์— ์†ํ•œ ๋ฉค๋ฒ„ ์•ก์…˜์„ ์‚ญ์ œํ•˜๋ฉด ์ดํ›„ ์ง€์ถœ ๋‚ด์—ญ ๋””ํ…Œ์ผ์ด ์ดˆ๊ธฐํ™”๋œ๋‹ค.") + @Test + void deleteMemberAction1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "ํ† ๋‹ค๋ฆฌ", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "ํ† ๋‹ค๋ฆฌ", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "์ฟ ํ‚ค", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "์›จ๋””", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "๊ฐ์ž", IN, 5L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5 + ) + ); + BillAction billAction = new BillAction(new Action(event, 6L), "๋ฝ•์กฑ", 100_000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "์ฟ ํ‚ค", 40_000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "์›จ๋””", 30_000L, false); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "๊ฐ์ž", 30_000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); + + memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); + + assertThat(billActionDetails).hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("ํ† ๋‹ค๋ฆฌ", 25_000L), + tuple("์ฟ ํ‚ค", 25_000L), + tuple("์›จ๋””", 25_000L), + tuple("๊ฐ์ž", 25_000L) + ); + } + + private MemberAction createMemberAction( + Action action, + String memberName, + MemberActionStatus memberActionStatus, + long memberGroupId + ) { + return new MemberAction(action, memberName, memberActionStatus, memberGroupId); + } +} diff --git a/server/src/test/java/server/haengdong/application/ServiceTestSupport.java b/server/src/test/java/server/haengdong/application/ServiceTestSupport.java new file mode 100644 index 000000000..b0e2db0a6 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/ServiceTestSupport.java @@ -0,0 +1,11 @@ +package server.haengdong.application; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import server.haengdong.support.extension.DatabaseCleanerExtension; + +@ExtendWith(DatabaseCleanerExtension.class) +@SpringBootTest(webEnvironment= WebEnvironment.NONE) +abstract class ServiceTestSupport { +} diff --git a/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java new file mode 100644 index 000000000..39c2d0bb8 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java @@ -0,0 +1,70 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.ActionService; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.presentation.ActionController; + +class ActionControllerDocsTest extends RestDocsSupport { + + private final ActionService actionService = mock(ActionService.class); + + @Override + protected Object initController() { + return new ActionController(actionService); + } + + @DisplayName("์ฐธ์—ฌ์ž๋ณ„ ์ •์‚ฐ ํ˜„ํ™ฉ์„ ์กฐํšŒํ•œ๋‹ค.") + @Test + void getMemberBillReports() throws Exception { + List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( + new MemberBillReportAppResponse("์†Œํ•˜", 20_000L), new MemberBillReportAppResponse("ํ† ๋‹ค๋ฆฌ", 200_000L)); + + given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/reports", "๋ง์ตธํ† ํฐ") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("์†Œํ•˜"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("ํ† ๋‹ค๋ฆฌ"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))) + .andDo( + document("getMemberBillReports", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID") + ), + responseFields( + fieldWithPath("reports").type(JsonFieldType.ARRAY).description("์ „์ฒด ์ •์‚ฐ ํ˜„ํ™ฉ ๋ชฉ๋ก"), + fieldWithPath("reports[0].name").type(JsonFieldType.STRING) + .description("์ฐธ์—ฌ์ž ์ด๋ฆ„"), + fieldWithPath("reports[0].price").type(JsonFieldType.NUMBER) + .description("์ฐธ์—ฌ์ž ์ •์‚ฐ ๊ธˆ์•ก") + )) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java new file mode 100644 index 000000000..7ed6fe6c4 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java @@ -0,0 +1,128 @@ +package server.haengdong.docs; + +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.BillActionService; +import server.haengdong.presentation.BillActionController; +import server.haengdong.presentation.request.BillActionSaveRequest; +import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +class BillActionControllerDocsTest extends RestDocsSupport { + + private final BillActionService billActionService = mock(BillActionService.class); + + @Override + protected Object initController() { + return new BillActionController(billActionService); + } + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ์„ ์ƒ์„ฑํ•œ๋‹ค.") + @Test + void saveAllBillAction() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("๋ฝ•์กฑ", 10_000L), + new BillActionSaveRequest("์ธ์ƒ๋งฅ์ฃผ", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "์ฟ ํ‚คํ† ํฐ"; + + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + .contentType(MediaType.APPLICATION_JSON) + .cookie(EVENT_COOKIE) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("createBillActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID") + ), + requestCookies( + cookieWithName("eventToken").description("ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž ํ† ํฐ") + ), + requestFields( + fieldWithPath("actions").description("์ƒ์„ฑํ•  ์ง€์ถœ ์•ก์…˜ ๋ชฉ๋ก"), + fieldWithPath("actions[0].title").description("์ƒ์„ฑํ•  ์ง€์ถœ ์•ก์…˜์˜ ์ œ๋ชฉ"), + fieldWithPath("actions[0].price").description("์ƒ์„ฑํ•  ์ง€์ถœ ์•ก์…˜์˜ ๊ธˆ์•ก") + ) + )); + } + + @DisplayName("์ง€์ถœ ์•ก์…˜์„ ์ˆ˜์ •ํ•œ๋‹ค.") + @Test + void updateBillAction() throws Exception { + BillActionUpdateRequest request = new BillActionUpdateRequest("๋ฝ•์กฑ", 10_000L); + + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "์›จ๋””ํ† ํฐ"; + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1L) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("updateBillAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID"), + parameterWithName("actionId").description("์ง€์ถœ ์•ก์…˜ ID") + ), + requestCookies( + cookieWithName("eventToken").description("ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž ํ† ํฐ") + ), + requestFields( + fieldWithPath("title").description("์ˆ˜์ •ํ•  ์ง€์ถœ ์•ก์…˜์˜ ์ œ๋ชฉ"), + fieldWithPath("price").description("์ˆ˜์ •ํ•  ์ง€์ถœ ์•ก์…˜์˜ ๊ธˆ์•ก") + ) + )); + } + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ์„ ์‚ญ์ œํ•œ๋‹ค.") + @Test + void deleteBillAction() throws Exception { + String eventId = "ํ† ๋‹ค๋ฆฌํ† ํฐ"; + + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1) + .cookie(EVENT_COOKIE) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("deleteBillAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID"), + parameterWithName("actionId").description("์ง€์ถœ ์•ก์…˜ ID") + ), + requestCookies( + cookieWithName("eventToken").description("ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž ํ† ํฐ") + ) + )); + } +} diff --git a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java new file mode 100644 index 000000000..f492195f3 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java @@ -0,0 +1,127 @@ +package server.haengdong.docs; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.BillActionDetailService; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.BillActionDetailController; +import server.haengdong.presentation.request.BillActionDetailUpdateRequest; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; + +public class BillActionDetailControllerDocsTest extends RestDocsSupport { + + private final BillActionDetailService billActionDetailService = mock(BillActionDetailService.class); + + @Override + protected Object initController() { + return new BillActionDetailController(billActionDetailService); + } + + @DisplayName("์ฐธ์—ฌ์ž๋ณ„ ์ง€์ถœ ๊ธˆ์•ก์„ ์กฐํšŒํ•œ๋‹ค.") + @Test + void findBillActionDetailsTest() throws Exception { + BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( + List.of(new BillActionDetailAppResponse("ํ† ๋‹ค๋ฆฌ", 1000L, false))); + given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) + .willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].name").value("ํ† ๋‹ค๋ฆฌ")) + .andExpect(jsonPath("$.members[0].price").value(1000L)) + .andExpect(jsonPath("$.members[0].isFixed").value(false)) + .andDo( + document("findBillActionDetailsTest", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID"), + parameterWithName("actionId").description("์•ก์…˜ ID") + ), requestCookies( + cookieWithName("eventToken").description("ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž ํ† ํฐ") + ), responseFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("์ „์ฒด ์ •์‚ฐ ์ˆ˜์ • ์š”์ฒญ ๋ชฉ๋ก"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("์ฐธ์—ฌ์ž ์ด๋ฆ„"), + fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) + .description("์ฐธ์—ฌ์ž ์ •์‚ฐ ๊ธˆ์•ก"), + fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) + .description("์ฐธ์—ฌ์ž ์ •์‚ฐ ๊ธˆ์•ก ์ˆ˜์ • ์—ฌ๋ถ€") + ) + ) + ); + } + + @DisplayName("์ฐธ์—ฌ์ž๋ณ„ ์ง€์ถœ ๊ธˆ์•ก์„ ์ˆ˜์ •ํ•œ๋‹ค.") + @Test + void updateBillActionDetailsTest() throws Exception { + List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + new BillActionDetailUpdateRequest("์†Œํ•˜", 10000L, true), + new BillActionDetailUpdateRequest("์›จ๋””", 20000L, true) + ); + BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + billActionDetailUpdateRequests); + + String json = objectMapper.writeValueAsString(request); + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateBillActionDetailsTest", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID"), + parameterWithName("actionId").description("์•ก์…˜ ID") + ), + requestCookies( + cookieWithName("eventToken").description("ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž ํ† ํฐ") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("์ „์ฒด ์ •์‚ฐ ์ˆ˜์ • ์š”์ฒญ ๋ชฉ๋ก"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("์ฐธ์—ฌ์ž ์ด๋ฆ„"), + fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) + .description("์ฐธ์—ฌ์ž ์ •์‚ฐ ๊ธˆ์•ก"), + fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) + .description("์ฐธ์—ฌ์ž ์ •์‚ฐ ๊ธˆ์•ก ์ˆ˜์ • ์—ฌ๋ถ€") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java new file mode 100644 index 000000000..88de2a3a6 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -0,0 +1,381 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.cookies.CookieDocumentation.responseCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.time.Duration; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.AuthService; +import server.haengdong.application.EventService; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.infrastructure.auth.CookieProperties; +import server.haengdong.presentation.EventController; +import server.haengdong.presentation.request.EventLoginRequest; +import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberNameUpdateRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; + +public class EventControllerDocsTest extends RestDocsSupport { + + private final EventService eventService = mock(EventService.class); + private final AuthService authService = mock(AuthService.class); + private final CookieProperties cookieProperties = new CookieProperties( + true, true, "domain", "path", "none", Duration.ofDays(7) + ); + + @Override + protected Object initController() { + return new EventController(eventService, authService, cookieProperties); + } + + @DisplayName("์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("ํ† ๋‹ค๋ฆฌ", "0987"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String eventId = "์ฟ ํ‚ค ํ† ํฐ"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + given(authService.createToken(eventId)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(jsonPath("$.eventId").value("์ฟ ํ‚ค ํ† ํฐ")) + .andDo( + document("createEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("ํ–‰์‚ฌ ์ด๋ฆ„"), + fieldWithPath("password").type(JsonFieldType.STRING).description("ํ–‰์‚ฌ ๋น„๋ฐ€ ๋ฒˆํ˜ธ") + ), + responseFields( + fieldWithPath("eventId").type(JsonFieldType.STRING) + .description("ํ–‰์‚ฌ ID") + ), + responseCookies( + cookieWithName("eventToken").description("ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž์šฉ ํ† ํฐ") + ) + ) + ); + } + + @DisplayName("ํ† ํฐ์œผ๋กœ ํ–‰์‚ฌ๋ฅผ ์กฐํšŒํ•œ๋‹ค.") + @Test + void findEventTest() throws Exception { + String eventId = "๋ง์ตธํ† ํฐ"; + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("ํ–‰๋™๋Œ€์žฅ ํšŒ์‹"); + given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); + + mockMvc.perform(get("/api/events/{eventId}", eventId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.eventName").value("ํ–‰๋™๋Œ€์žฅ ํšŒ์‹")) + .andDo( + document("getEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID") + ), + responseFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("ํ–‰์‚ฌ ์ด๋ฆ„") + ) + ) + ); + } + + @DisplayName("ํ–‰์‚ฌ์— ์ฐธ์—ฌํ•œ ์ „์ฒด ์ธ์›์„ ์ค‘๋ณต ์—†์ด ์กฐํšŒํ•œ๋‹ค.") + @Test + void findAllMembersTest() throws Exception { + MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("ํ† ๋‹ค๋ฆฌ", "์ฟ ํ‚ค")); + given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames").isArray()) + .andExpect(jsonPath("$.memberNames[0]").value("ํ† ๋‹ค๋ฆฌ")) + .andExpect(jsonPath("$.memberNames[1]").value("์ฟ ํ‚ค")) + .andDo( + document("findAllEventMember", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("ํ–‰์‚ฌ ์ฐธ์—ฌ์ž ๋ชฉ๋ก") + ) + ) + ); + } + + @DisplayName("ํ–‰์‚ฌ ์ฐธ์—ฌ ์ธ์›์˜ ์ด๋ฆ„์„ ์ˆ˜์ •ํ•œ๋‹ค.") + @Test + void updateMember() throws Exception { + String token = "TOKEN"; + MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( + new MemberNameUpdateRequest("ํ† ๋‹ค๋ง", "ํ† ์Ÿ์ด"), + new MemberNameUpdateRequest("๊ฐ์ž", "๊ณ ๊ตฌ๋งˆ") + )); + + String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + + mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateEventMemberName", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID") + ), + requestCookies( + cookieWithName("eventToken").description("ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž ํ† ํฐ") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY).description("์ˆ˜์ •ํ•  ์ฐธ์—ฌ์ž ๋ชฉ๋ก"), + fieldWithPath("members[].before").type(JsonFieldType.STRING) + .description("์ˆ˜์ • ์ „ ์ฐธ์—ฌ์ž ์ด๋ฆ„"), + fieldWithPath("members[].after").type(JsonFieldType.STRING) + .description("์ˆ˜์ • ํ›„ ์ฐธ์—ฌ์ž ์ด๋ฆ„") + ) + ) + ); + } + + @DisplayName("ํ–‰์‚ฌ ์–ด๋“œ๋ฏผ์ด ๋กœ๊ทธ์ธํ•œ๋‹ค.") + @Test + void loginEvent() throws Exception { + String token = "TOKEN"; + EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); + String requestBody = objectMapper.writeValueAsString(eventLoginRequest); + given(authService.createToken(token)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events/{eventId}/login", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(status().isOk()) + .andDo( + document("eventLogin", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID") + ), + requestFields( + fieldWithPath("password").type(JsonFieldType.STRING) + .description("ํ–‰์‚ฌ ๋น„๋ฐ€ ๋ฒˆํ˜ธ") + ), + responseCookies( + cookieWithName("eventToken").description("ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž์šฉ ํ† ํฐ") + ) + ) + ); + } + + @DisplayName("ํ–‰์‚ฌ ์ „์ฒด ์•ก์…˜ ์ด๋ ฅ ์กฐํšŒ") + @Test + void findActions() throws Exception { + String token = "TOKEN"; + List<ActionAppResponse> actionAppResponses = List.of( + new ActionAppResponse(1L, "๋ง์ตธ", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "์กฑ๋ฐœ", 100L, 2L, ActionType.BILL), + new ActionAppResponse(3L, "์ธ์ƒ๋„ค์ปท", 1000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "๋ง์ตธ", null, 4L, ActionType.OUT) + ); + given(eventService.findActions(token)).willReturn(actionAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions", token) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) + .andExpect(jsonPath("$.steps[0].stepName").value(equalTo("0์ฐจ"))) + .andExpect(jsonPath("$.steps[0].members[0]").value(equalTo("๋ง์ตธ"))) + .andExpect(jsonPath("$.steps[0].actions[0].actionId").value(equalTo(1))) + .andExpect(jsonPath("$.steps[0].actions[0].name").value(equalTo("๋ง์ตธ"))) + .andExpect(jsonPath("$.steps[0].actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.steps[0].actions[0].sequence").value(equalTo(1))) + + .andExpect(jsonPath("$.steps[1].type").value(equalTo("BILL"))) + .andExpect(jsonPath("$.steps[1].stepName").value(equalTo("1์ฐจ"))) + .andExpect(jsonPath("$.steps[1].members[0]").value(equalTo("๋ง์ตธ"))) + .andExpect(jsonPath("$.steps[1].actions[0].actionId").value(equalTo(2))) + .andExpect(jsonPath("$.steps[1].actions[0].name").value(equalTo("์กฑ๋ฐœ"))) + .andExpect(jsonPath("$.steps[1].actions[0].price").value(equalTo(100))) + .andExpect(jsonPath("$.steps[1].actions[0].sequence").value(equalTo(2))) + + .andExpect(jsonPath("$.steps[1].actions[1].actionId").value(equalTo(3))) + .andExpect(jsonPath("$.steps[1].actions[1].name").value(equalTo("์ธ์ƒ๋„ค์ปท"))) + .andExpect(jsonPath("$.steps[1].actions[1].price").value(equalTo(1000))) + .andExpect(jsonPath("$.steps[1].actions[1].sequence").value(equalTo(3))) + + .andExpect(jsonPath("$.steps[2].type").value(equalTo("OUT"))) + .andExpect(jsonPath("$.steps[2].stepName").value(equalTo("1์ฐจ"))) + .andExpect(jsonPath("$.steps[2].actions[0].actionId").value(equalTo(4))) + .andExpect(jsonPath("$.steps[2].actions[0].name").value(equalTo("๋ง์ตธ"))) + .andExpect(jsonPath("$.steps[2].actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.steps[2].actions[0].sequence").value(equalTo(4))) + + .andDo( + document("findActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID") + ), + responseFields( + fieldWithPath("steps[].stepName").type(JsonFieldType.STRING) + .description("์Šคํƒญ ์ด๋ฆ„"), + fieldWithPath("steps[].type").type(JsonFieldType.STRING) + .description("์•ก์…˜ ์œ ํ˜• [BILL, IN, OUT]"), + fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) + .description("ํ•ด๋‹น step์— ์ฐธ์—ฌํ•œ ์ฐธ์—ฌ์ž ๋ชฉ๋ก"), + fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) + .description("์•ก์…˜ ID"), + fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) + .description("์ฐธ์—ฌ์ž ์•ก์…˜์ผ ๊ฒฝ์šฐ ์ฐธ์—ฌ์ž ์ด๋ฆ„, ์ง€์ถœ ์•ก์…˜์ผ ๊ฒฝ์šฐ ์ง€์ถœ ๋‚ด์—ญ ์ด๋ฆ„"), + fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() + .description("์ฐธ์—ฌ์ž ์•ก์…˜์ผ ๊ฒฝ์šฐ null, ์ง€์ถœ ์•ก์…˜์ผ ๊ฒฝ์šฐ ์ง€์ถœ ๊ธˆ์•ก"), + fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) + .description("์•ก์…˜ ์ˆœ์„œ"), + fieldWithPath("steps[].actions[].isFixed").type(JsonFieldType.BOOLEAN) + .description("์ง€์ถœ ๋‚ด์—ญ์˜ ๋ฉค๋ฒ„๋ณ„ ๊ณ ์ • ์ง€์ถœ ๊ธˆ์•ก ์ƒ์„ฑ ์—ฌ๋ถ€") + ) + ) + ); + } + + @DisplayName("ํ–‰์‚ฌ ์ „์ฒด ์•ก์…˜ ์ด๋ ฅ ์กฐํšŒ v2") + @Test + void findActions2() throws Exception { + String token = "TOKEN"; + List<ActionAppResponse> actionAppResponses = List.of( + new ActionAppResponse(1L, "๋ง์ตธ", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "์กฑ๋ฐœ", 100L, 2L, ActionType.BILL), + new ActionAppResponse(3L, "์ธ์ƒ๋„ค์ปท", 1000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "๋ง์ตธ", null, 4L, ActionType.OUT) + ); + given(eventService.findActions(token)).willReturn(actionAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/v2", token) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.actions[0].actionId").value(equalTo(1))) + .andExpect(jsonPath("$.actions[0].name").value(equalTo("๋ง์ตธ"))) + .andExpect(jsonPath("$.actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.actions[0].sequence").value(equalTo(1))) + .andExpect(jsonPath("$.actions[0].type").value(equalTo("IN"))) + + .andExpect(jsonPath("$.actions[1].actionId").value(equalTo(2))) + .andExpect(jsonPath("$.actions[1].name").value(equalTo("์กฑ๋ฐœ"))) + .andExpect(jsonPath("$.actions[1].price").value(equalTo(100))) + .andExpect(jsonPath("$.actions[1].sequence").value(equalTo(2))) + .andExpect(jsonPath("$.actions[1].type").value(equalTo("BILL"))) + + .andExpect(jsonPath("$.actions[2].actionId").value(equalTo(3))) + .andExpect(jsonPath("$.actions[2].name").value(equalTo("์ธ์ƒ๋„ค์ปท"))) + .andExpect(jsonPath("$.actions[2].price").value(equalTo(1000))) + .andExpect(jsonPath("$.actions[2].sequence").value(equalTo(3))) + .andExpect(jsonPath("$.actions[2].type").value(equalTo("BILL"))) + + .andExpect(jsonPath("$.actions[3].actionId").value(equalTo(4))) + .andExpect(jsonPath("$.actions[3].name").value(equalTo("๋ง์ตธ"))) + .andExpect(jsonPath("$.actions[3].price").value(equalTo(null))) + .andExpect(jsonPath("$.actions[3].sequence").value(equalTo(4))) + .andExpect(jsonPath("$.actions[3].type").value(equalTo("OUT"))) + + .andDo( + document("findActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID") + ), + responseFields( + fieldWithPath("actions[].actionId").type(JsonFieldType.NUMBER) + .description("์•ก์…˜ ID"), + fieldWithPath("actions[].name").type(JsonFieldType.STRING) + .description("์ฐธ์—ฌ์ž ์•ก์…˜์ผ ๊ฒฝ์šฐ ์ฐธ์—ฌ์ž ์ด๋ฆ„, ์ง€์ถœ ์•ก์…˜์ผ ๊ฒฝ์šฐ ์ง€์ถœ ๋‚ด์—ญ ์ด๋ฆ„"), + fieldWithPath("actions[].price").type(JsonFieldType.NUMBER).optional() + .description("์ฐธ์—ฌ์ž ์•ก์…˜์ผ ๊ฒฝ์šฐ null, ์ง€์ถœ ์•ก์…˜์ผ ๊ฒฝ์šฐ ์ง€์ถœ ๊ธˆ์•ก"), + fieldWithPath("actions[].sequence").type(JsonFieldType.NUMBER) + .description("์•ก์…˜ ์ˆœ์„œ"), + fieldWithPath("actions[].type").type(JsonFieldType.STRING) + .description("์•ก์…˜ ํƒ€์ž…") + ) + ) + ); + } + + @DisplayName("ํ–‰์‚ฌ ์–ด๋“œ๋ฏผ ๊ถŒํ•œ์„ ํ™•์ธํ•œ๋‹ค.") + @Test + void authenticateTest() throws Exception { + String token = "TOKEN"; + mockMvc.perform(post("/api/events/{eventId}/auth", token) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + + .andDo( + document("authenticateEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID") + ), + requestCookies( + cookieWithName("eventToken").description("ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž ํ† ํฐ").optional() + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java new file mode 100644 index 000000000..afd766c8f --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java @@ -0,0 +1,157 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.MemberActionService; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.MemberActionController; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +public class MemberActionControllerDocsTest extends RestDocsSupport { + + private final MemberActionService memberActionService = mock(MemberActionService.class); + + @Override + protected Object initController() { + return new MemberActionController(memberActionService); + } + + @DisplayName("์ฐธ์—ฌ์ž ํ–‰๋™์„ ์ถ”๊ฐ€ํ•œ๋‹ค.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( + List.of("์›จ๋””", "์†Œํ•˜", "ํ† ๋‹ค๋ฆฌ", "์ฟ ํ‚ค"), "IN"); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/events/{eventId}/member-actions", "๋ง์ตธํ† ํฐ") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("createMemberAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID") + ), + requestCookies( + cookieWithName("eventToken").description("ํ† ํฐ ํ† ํฐ") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("์•ก์…˜ ๋Œ€์ƒ ์ฐธ์—ฌ์ž ๋ชฉ๋ก"), + fieldWithPath("status").type(JsonFieldType.STRING) + .description("์ฐธ์—ฌ์ž ์•ก์…˜ ์ƒํƒœ [IN(๋Šฆ์ฐธ), OUT(ํƒˆ์ฃผ)]") + ) + ) + ); + } + + @DisplayName("ํ˜„์žฌ ์ฐธ์—ฌ ์ธ์›์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.") + @Test + void getCurrentMembers() throws Exception { + List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( + new CurrentMemberAppResponse("์†Œํ•˜"), new CurrentMemberAppResponse("ํ† ๋‹ค๋ฆฌ")); + + given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "๋ง์ตธํ† ํฐ") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames[0]").value(equalTo("์†Œํ•˜"))) + .andExpect(jsonPath("$.memberNames[1]").value(equalTo("ํ† ๋‹ค๋ฆฌ"))) + .andDo( + document("getCurrentMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("ํ˜„์žฌ ํƒˆ์ฃผ ๊ฐ€๋Šฅํ•œ ์ฐธ์—ฌ ์ธ์› ์ด๋ฆ„ ๋ชฉ๋ก") + ) + ) + ); + } + + @DisplayName("์ด๋ฒคํŠธ์— ์†ํ•œ ๋ฉค๋ฒ„ ์•ก์…˜์„ ์‚ญ์ œํ•˜๋ฉด ์ดํ›„์— ๊ธฐ๋ก๋œ ํ•ด๋‹น ์ฐธ์—ฌ์ž์˜ ๋ชจ๋“  ๋ฉค๋ฒ„ ์•ก์…˜์„ ์‚ญ์ œํ•œ๋‹ค.") + @Test + void deleteMemberAction() throws Exception { + String eventId = "๋ง์ตธํ† ํฐ"; + Long actionId = 2L; + + mockMvc.perform(delete("/api/events/{eventId}/member-actions/{actionId}", eventId, actionId) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteMemberAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID"), + parameterWithName("actionId").description("์•ก์…˜ ID") + ), + requestCookies( + cookieWithName("eventToken").description("ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž์šฉ ํ† ํฐ") + ) + ) + ); + } + + @DisplayName("ํ–‰์‚ฌ์˜ ์ „์ฒด ์ฐธ์—ฌ์ž ์ค‘์—์„œ ํŠน์ • ์ฐธ์—ฌ์ž์˜ ๋งด๋ฒ„ ์•ก์…˜์„ ์ „๋ถ€ ์‚ญ์ œํ•œ๋‹ค.") + @Test + void deleteMember() throws Exception { + String eventId = "๋ง์ตธํ† ํฐ"; + String memberName = "ํ–‰๋™๋Œ€์žฅ"; + + mockMvc.perform(delete("/api/events/{eventId}/members/{memberName}", eventId, memberName) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteAllMemberActionByName", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("ํ–‰์‚ฌ ID"), + parameterWithName("memberName").description("ํ–‰์‚ฌ ์ฐธ์—ฌ์ž ์ด๋ฆ„") + ), + requestCookies( + cookieWithName("eventToken").description("ํ–‰์‚ฌ ๊ด€๋ฆฌ์ž์šฉ ํ† ํฐ") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/RestDocsSupport.java b/server/src/test/java/server/haengdong/docs/RestDocsSupport.java new file mode 100644 index 000000000..3e6901ba8 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/RestDocsSupport.java @@ -0,0 +1,28 @@ +package server.haengdong.docs; + +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +@ExtendWith({RestDocumentationExtension.class}) +abstract class RestDocsSupport { + + protected MockMvc mockMvc; + + protected ObjectMapper objectMapper = new ObjectMapper(); + + @BeforeEach + void setUp(RestDocumentationContextProvider restDocumentation) { + this.mockMvc = MockMvcBuilders.standaloneSetup(initController()) + .apply(documentationConfiguration(restDocumentation)) + .build(); + } + + protected abstract Object initController(); +} diff --git a/server/src/test/java/server/haengdong/domain/action/ActionTest.java b/server/src/test/java/server/haengdong/domain/action/ActionTest.java new file mode 100644 index 000000000..6ff25479c --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/ActionTest.java @@ -0,0 +1,31 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; +import server.haengdong.support.fixture.Fixture; + +class ActionTest { + + @DisplayName("์•ก์…˜์˜ ์ดˆ๊ธฐ ์ˆœ์„œ๋ฒˆํ˜ธ๋Š” 1์ด๋‹ค.") + @Test + void createFirst() { + Event event = Fixture.EVENT1; + Action action = Action.createFirst(event); + + assertThat(action.getSequence()).isOne(); + } + + @DisplayName("ํ˜„์žฌ ์•ก์…˜์˜ ๋‹ค์Œ ์•ก์…˜์˜ ์ˆœ์„œ๋Š” 1๋งŒํผ ์ฆ๊ฐ€ํ•œ๋‹ค.") + @Test + void next() { + Event event = Fixture.EVENT1; + Action action = new Action(event, 2L); + + Action nextAction = action.next(); + + assertThat(nextAction.getSequence()).isEqualTo(3L); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java new file mode 100644 index 000000000..ba1ab36f2 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java @@ -0,0 +1,89 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; +import static server.haengdong.support.fixture.Fixture.EVENT1; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongException; + +class BillActionTest { + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ ์ œ๋ชฉ์˜ ์•ž๋’ค ๊ณต๋ฐฑ์„ ์ œ๊ฑฐํ•œ ๊ธธ์ด๊ฐ€ 1 ~ 30์ž๊ฐ€ ์•„๋‹ˆ๋ฉด ์ง€์ถœ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "1234567890123456789012345678901"}) + void validateTitle(String title) { + Event event = EVENT1; + Action action = new Action(event, 1L); + Long price = 100L; + + assertThatThrownBy(() -> new BillAction(action, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("์•ž๋’ค ๊ณต๋ฐฑ์„ ์ œ๊ฑฐํ•œ ์ง€์ถœ ๋‚ด์—ญ ์ œ๋ชฉ์€ 1 ~ 30์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + + @DisplayName("๊ธˆ์•ก์ด 10,000,000 ์ดํ•˜์˜ ์ž์—ฐ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ฉด ์ง€์ถœ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.") + @ParameterizedTest + @ValueSource(longs = {0, 10_000_001, 20_000_000}) + void validatePrice(long price) { + Event event = EVENT1; + Action action = new Action(event, 1L); + String title = "title"; + + assertThatThrownBy(() -> new BillAction(action, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("์ง€์ถœ ๊ธˆ์•ก์€ 10,000,000 ์ดํ•˜์˜ ์ž์—ฐ์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ƒ์„ฑํ•œ๋‹ค.") + @Test + void createBillAction() { + Event event = EVENT1; + Action action = new Action(event, 1L); + String title = "title"; + Long price = 1_000L; + + BillAction billAction = new BillAction(action, title, price); + + assertAll( + () -> assertThat(billAction.getAction()).isEqualTo(action), + () -> assertThat(billAction.getTitle()).isEqualTo(title), + () -> assertThat(billAction.getPrice()).isEqualTo(price) + ); + } + + @DisplayName("์ง€์ถœ ์•ก์…˜์— ๋ฉค๋ฒ„๋ณ„ ๊ณ ์ • ๊ธˆ์•ก์ด ์„ค์ •๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.") + @Test + void isFixed1() { + BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "์ธ์ƒ๋„ค์ปท", 2_000L); + + List<BillActionDetail> unfixedBillActionDetails = List.of( + new BillActionDetail(BILL_ACTION, "๊ฐ์ž", 1_000L, false), + new BillActionDetail(BILL_ACTION, "๊ณ ๊ตฌ๋งˆ", 1_000L, false) + ); + fixedBillAction.addDetails(unfixedBillActionDetails); + + assertThat(fixedBillAction.isFixed()).isEqualTo(false); + } + + @DisplayName("์ง€์ถœ ์•ก์…˜์— ๋ฉค๋ฒ„๋ณ„ ๊ณ ์ • ๊ธˆ์•ก์ด ์„ค์ •๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.") + @Test + void isFixed2() { + BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "์ธ์ƒ๋„ค์ปท", 5_000L); + + List<BillActionDetail> unfixedBillActionDetails = List.of( + new BillActionDetail(BILL_ACTION, "๊ฐ์ž", 4_000L, true), + new BillActionDetail(BILL_ACTION, "๊ณ ๊ตฌ๋งˆ", 1_000L, true) + ); + fixedBillAction.addDetails(unfixedBillActionDetails); + + assertThat(fixedBillAction.isFixed()).isEqualTo(true); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java new file mode 100644 index 000000000..93148abd3 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java @@ -0,0 +1,97 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class CurrentMembersTest { + + @DisplayName("์ธ์› ๋ณ€๋™ ์ด๋ ฅ์œผ๋กœ ํ˜„์žฌ ์ฐธ์—ฌ ์ธ์›์„ ๊ณ„์‚ฐํ•œ๋‹ค.") + @Test + void of() { + Event event = Fixture.EVENT1; + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(event, 1L), "๋ง์ตธ", IN, 1L), + new MemberAction(new Action(event, 2L), "๋ฐฑํ˜ธ", IN, 1L), + new MemberAction(new Action(event, 3L), "๋ฐฑํ˜ธ", OUT, 1L), + new MemberAction(new Action(event, 4L), "์›จ๋””", IN, 1L) + ); + + CurrentMembers currentMembers = CurrentMembers.of(memberActions); + + assertThat(currentMembers.getMembers()) + .containsExactlyInAnyOrder("๋ง์ตธ", "์›จ๋””"); + } + + @DisplayName("์ธ์› ๋ณ€๋™ ์•ก์…˜์˜ ์ƒํƒœ๊ฐ€ IN์ด๋ฉด ํ˜„์žฌ ์ธ์›์— ์ถ”๊ฐ€ํ•œ๋‹ค.") + @Test + void addMemberAction1() { + CurrentMembers currentMembers = new CurrentMembers(); + Event event = Fixture.EVENT1; + MemberAction memberAction = new MemberAction(new Action(event, 1L), "์›จ๋””", IN, 1L); + + CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction); + Set<String> members = addedCurrentMembers.getMembers(); + + assertThat(members).hasSize(1) + .containsExactly("์›จ๋””"); + } + + @DisplayName("์ธ์› ๋ณ€๋™ ์•ก์…˜์˜ ์ƒํƒœ๊ฐ€ OUT์ด๋ฉด ํ˜„์žฌ ์ธ์›์—์„œ ์ œ์™ธํ•œ๋‹ค.") + @Test + void addMemberAction2() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "์›จ๋””", IN, 1L); + CurrentMembers currentMembers = new CurrentMembers().addMemberAction(memberAction1); + MemberAction memberAction2 = new MemberAction(new Action(event, 1L), "์›จ๋””", OUT, 1L); + + CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction2); + + assertThat(addedCurrentMembers.getMembers()).hasSize(0); + } + + @DisplayName("ํ˜„์žฌ ์ฐธ์—ฌ์ค‘์ธ ์ธ์›์€ ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.") + @Test + void validate1() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("ํ† ๋‹ค๋ฆฌ")); + + assertThatCode(() -> currentMembers.validate("ํ† ๋‹ค๋ฆฌ", OUT)) + .doesNotThrowAnyException(); + } + + @DisplayName("ํ˜„์žฌ ์ฐธ์—ฌ์ค‘์ด์ง€ ์•Š์€ ์ธ์›์€ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋‹ค.") + @Test + void validate2() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("์ฟ ํ‚ค")); + + assertThatCode(() -> currentMembers.validate("ํ† ๋‹ค๋ฆฌ", IN)) + .doesNotThrowAnyException(); + } + + @DisplayName("ํ˜„์žฌ ์ฐธ์—ฌ์ค‘์ธ ์ธ์›์€ ๋“ค์–ด์˜ฌ ์ˆ˜ ์—†๋‹ค.") + @Test + void validate3() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("ํ† ๋‹ค๋ฆฌ")); + + assertThatCode(() -> currentMembers.validate("ํ† ๋‹ค๋ฆฌ", IN)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("ํ˜„์žฌ ์ฐธ์—ฌ์ค‘์ด์ง€ ์•Š์€ ์ธ์›์€ ๋‚˜๊ฐˆ ์ˆ˜ ์—†๋‹ค.") + @Test + void validate4() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("์ฟ ํ‚ค")); + + assertThatCode(() -> currentMembers.validate("ํ† ๋‹ค๋ฆฌ", OUT)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java new file mode 100644 index 000000000..02070a537 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java @@ -0,0 +1,56 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; +import server.haengdong.support.fixture.Fixture; + +class MemberBillReportTest { + + @DisplayName("์•ก์…˜ ๋ชฉ๋ก์œผ๋กœ ์ฐธ๊ฐ€์ž ์ •์‚ฐ ๋ฆฌํฌํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.") + @Test + void createByActions() { + Event event = Fixture.EVENT1; + List<BillAction> billActions = List.of( + new BillAction(new Action(event, 4L), "๋ฝ•์กฑ", 60_000L), + new BillAction(new Action(event, 7L), "์ธ์ƒ๋„ค์ปท", 20_000L) + ); + billActions.get(0).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "์†Œํ•˜", 10_000L, false), + new BillActionDetail(BILL_ACTION, "๊ฐ์ž", 40_000L, true), + new BillActionDetail(BILL_ACTION, "์ฟ ํ‚ค", 10_000L, false) + ) + ); + billActions.get(1).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "์†Œํ•˜", 5_000L, true), + new BillActionDetail(BILL_ACTION, "์ฟ ํ‚ค", 15_000L, true) + ) + ); + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(event, 1L), "์†Œํ•˜", IN, 1L), + new MemberAction(new Action(event, 2L), "๊ฐ์ž", IN, 1L), + new MemberAction(new Action(event, 3L), "์ฟ ํ‚ค", IN, 1L), + new MemberAction(new Action(event, 5L), "๊ฐ์ž", OUT, 2L) + ); + + MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); + + assertThat(memberBillReport.getReports()) + .containsAllEntriesOf( + Map.of( + "๊ฐ์ž", 40_000L, + "์ฟ ํ‚ค", 25_000L, + "์†Œํ•˜", 15_000L + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java new file mode 100644 index 000000000..12c0c0569 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/event/EventTest.java @@ -0,0 +1,65 @@ +package server.haengdong.domain.event; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.exception.HaengdongException; + +class EventTest { + + @DisplayName("๊ณต๋ฐฑ ๋ฌธ์ž๊ฐ€ ์—ฐ์†๋˜์ง€ ์•Š๊ณ , ์ด๋ฆ„์ด 2์ž ์ด์ƒ 20์ž ์ดํ•˜์ธ ํ–‰์‚ฌ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.") + @ParameterizedTest + @ValueSource(strings = {"12", "12345678901234567890", "๊ณต ๋ฐฑ", " ๊ณต๋ฐฑ", "๊ณต๋ฐฑ ", " ๊ณต ๋ฐฑ "}) + void createSuccessTest(String eventName) { + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) + .doesNotThrowAnyException(); + } + + @DisplayName("๊ณต๋ฐฑ ๋ฌธ์ž๊ฐ€ ์—ฐ์†๋˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.") + @ParameterizedTest + @ValueSource(strings = {" ๊ณต๋ฐฑ", "๊ณต๋ฐฑ ", "๊ณต๋ฐฑ ์—ฐ์†", "๊ณต ๋ฐฑ"}) + void createFailTest1(String eventName) { + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage(String.format("ํ–‰์‚ฌ ์ด๋ฆ„์—๋Š” ๊ณต๋ฐฑ ๋ฌธ์ž๊ฐ€ ์—ฐ์†๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ์ด๋ฆ„ : %s", eventName)); + } + + @DisplayName("์ด๋ฆ„์ด 1์ž ๋ฏธ๋งŒ์ด๊ฑฐ๋‚˜ 20์ž ์ดˆ๊ณผ์ธ ๊ฒฝ์šฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "123456789012345678901"}) + void createFilTest2(String eventName) { + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage(String.format("ํ–‰์‚ฌ ์ด๋ฆ„์€ 1์ž ์ด์ƒ 20์ž ์ดํ•˜๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ์ด๋ฆ„ ๊ธธ์ด : %d", eventName.length())); + } + + @DisplayName("๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” 4์ž๋ฆฌ ์ˆซ์ž ์ž…๋‹ˆ๋‹ค.") + @ParameterizedTest + @ValueSource(strings = {"1", "12", "123", "12345", "adgd"}) + void validatePassword(String password) { + assertThatCode(() -> new Event("์ด๋ฆ„", password, "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฅธ์ง€ ๊ฒ€์ฆํ•œ๋‹ค.") + @Test + void isNotSamePassword() { + String rawPassword = "1234"; + Event event = new Event("์ด๋ฆ„", rawPassword, "TEST_TOKEN"); + + assertThat(event.isPasswordMismatch(rawPassword)).isFalse(); + } + + @DisplayName("๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฅธ์ง€ ๊ฒ€์ฆํ•œ๋‹ค.") + @Test + void isNotSamePassword1() { + String rawPassword = "1234"; + Event event = new Event("์ด๋ฆ„", "5678", "TEST_TOKEN"); + + assertThat(event.isPasswordMismatch(rawPassword)).isTrue(); + } +} diff --git a/server/src/test/java/server/haengdong/domain/event/PasswordTest.java b/server/src/test/java/server/haengdong/domain/event/PasswordTest.java new file mode 100644 index 000000000..c504d3aa2 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/event/PasswordTest.java @@ -0,0 +1,19 @@ +package server.haengdong.domain.event; + +import static org.assertj.core.api.Assertions.assertThatCode; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.exception.HaengdongException; + +class PasswordTest { + + @DisplayName("๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” 4์ž๋ฆฌ ์ˆซ์ž ์ž…๋‹ˆ๋‹ค.") + @ParameterizedTest + @ValueSource(strings = {"1", "12", "123", "12345", "adgd"}) + void validatePassword(String rawPassword) { + assertThatCode(() -> new Password(rawPassword)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java new file mode 100644 index 000000000..1de5889b5 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java @@ -0,0 +1,36 @@ +package server.haengdong.presentation; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.response.MemberBillReportAppResponse; + +class ActionControllerTest extends ControllerTestSupport { + + @DisplayName("์ฐธ์—ฌ์ž๋ณ„ ์ •์‚ฐ ํ˜„ํ™ฉ์„ ์กฐํšŒํ•œ๋‹ค.") + @Test + void getMemberBillReports() throws Exception { + List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( + new MemberBillReportAppResponse("์†Œํ•˜", 20_000L), new MemberBillReportAppResponse("ํ† ๋‹ค๋ฆฌ", 200_000L)); + + given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/reports", "๋ง์ตธํ† ํฐ") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("์†Œํ•˜"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("ํ† ๋‹ค๋ฆฌ"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java new file mode 100644 index 000000000..4420e369c --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -0,0 +1,97 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; +import server.haengdong.presentation.request.BillActionSaveRequest; +import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +class BillActionControllerTest extends ControllerTestSupport { + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ์„ ์ƒ์„ฑํ•œ๋‹ค.") + @Test + void saveAllBillAction() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("๋ฝ•์กฑ", 10_000L), + new BillActionSaveRequest("์ธ์ƒ๋งฅ์ฃผ", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "์ฟ ํ‚คํ† ํฐ"; + + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("title์ด ๋น„์–ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ง€์ถœ ๋‚ด์—ญ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void saveAllBillAction1() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("", 10_000L), + new BillActionSaveRequest("์ธ์ƒ๋งฅ์ฃผ", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "์†Œํ•˜ํ† ํฐ"; + + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isBadRequest()); + } + + @DisplayName("์ง€์ถœ ์•ก์…˜์„ ์ˆ˜์ •ํ•œ๋‹ค.") + @Test + void updateBillAction() throws Exception { + BillActionUpdateRequest request = new BillActionUpdateRequest("๋ฝ•์กฑ", 10_000L); + + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "์›จ๋””ํ† ํฐ"; + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1L) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("์ง€์ถœ ๋‚ด์—ญ์„ ์‚ญ์ œํ•œ๋‹ค.") + @Test + void deleteBillAction() throws Exception { + String eventId = "ํ† ๋‹ค๋ฆฌํ† ํฐ"; + + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ–‰์‚ฌ์— ๋Œ€ํ•œ ์ง€์ถœ ๋‚ด์—ญ์„ ์‚ญ์ œํ•  ์ˆ˜ ์—†๋‹ค.") + @Test + void deleteBillAction1() throws Exception { + String eventId = "์ด์ƒํ•ดํ† ํฐ"; + doThrow(new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)) + .when(billActionService).deleteBillAction(any(String.class), any(Long.class)); + + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + .andDo(print()) + .andExpect(status().isBadRequest()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java new file mode 100644 index 000000000..6b595ee27 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java @@ -0,0 +1,56 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.request.BillActionDetailUpdateRequest; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; + +class BillActionDetailControllerTest extends ControllerTestSupport { + + @DisplayName("์ฐธ์—ฌ์ž๋ณ„ ์ง€์ถœ ๊ธˆ์•ก์„ ์กฐํšŒํ•œ๋‹ค.") + @Test + void findBillActionDetails() throws Exception { + BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( + List.of(new BillActionDetailAppResponse("ํ† ๋‹ค๋ฆฌ", 1000L, false))); + given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) + .willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].name").value("ํ† ๋‹ค๋ฆฌ")) + .andExpect(jsonPath("$.members[0].price").value(1000L)); + } + + @DisplayName("์ฐธ์—ฌ์ž๋ณ„ ์ง€์ถœ ๊ธˆ์•ก์„ ์ˆ˜์ •ํ•œ๋‹ค.") + @Test + void updateBillActionDetailsTest() throws Exception { + List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + new BillActionDetailUpdateRequest("์†Œํ•˜", 10000L, true), + new BillActionDetailUpdateRequest("์›จ๋””", 20000L, true) + ); + BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + billActionDetailUpdateRequests); + + String json = objectMapper.writeValueAsString(request); + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java new file mode 100644 index 000000000..46489b1a5 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java @@ -0,0 +1,53 @@ +package server.haengdong.presentation; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import server.haengdong.application.ActionService; +import server.haengdong.application.AuthService; +import server.haengdong.application.BillActionDetailService; +import server.haengdong.application.BillActionService; +import server.haengdong.application.EventService; +import server.haengdong.application.MemberActionService; + +@WebMvcTest( + controllers = { + EventController.class, + ActionController.class, + BillActionController.class, + MemberActionController.class, + BillActionDetailController.class + }, + excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {WebMvcConfigurer.class})} +) +abstract class ControllerTestSupport { + + @Autowired + protected MockMvc mockMvc; + + @Autowired + protected ObjectMapper objectMapper; + + @MockBean + protected EventService eventService; + + @MockBean + protected AuthService authService; + + @MockBean + protected ActionService actionService; + + @MockBean + protected MemberActionService memberActionService; + + @MockBean + protected BillActionService billActionService; + + @MockBean + protected BillActionDetailService billActionDetailService; +} diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java new file mode 100644 index 000000000..fcfe48d01 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -0,0 +1,111 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.presentation.request.EventLoginRequest; +import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberNameUpdateRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; + + +class EventControllerTest extends ControllerTestSupport { + + @DisplayName("์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("ํ† ๋‹ค๋ฆฌ", "0987"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String eventId = "๋ง์ตธํ† ํฐ"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + given(authService.createToken(eventId)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(jsonPath("$.eventId").value("๋ง์ตธํ† ํฐ")); + } + + @DisplayName("ํ† ํฐ์œผ๋กœ ํ–‰์‚ฌ๋ฅผ ์กฐํšŒํ•œ๋‹ค.") + @Test + void findEventTest() throws Exception { + String eventId = "๋ง์ตธํ† ํฐ"; + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("ํ–‰๋™๋Œ€์žฅ ํšŒ์‹"); + given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); + + mockMvc.perform(get("/api/events/{eventId}", eventId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.eventName").value("ํ–‰๋™๋Œ€์žฅ ํšŒ์‹")); + } + + @DisplayName("ํ–‰์‚ฌ์— ์ฐธ์—ฌํ•œ ์ „์ฒด ์ธ์›์„ ์ค‘๋ณต ์—†์ด ์กฐํšŒํ•œ๋‹ค.") + @Test + void findAllMembersTest() throws Exception { + MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("ํ† ๋‹ค๋ฆฌ", "์ฟ ํ‚ค")); + given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames").isArray()) + .andExpect(jsonPath("$.memberNames[0]").value("ํ† ๋‹ค๋ฆฌ")) + .andExpect(jsonPath("$.memberNames[1]").value("์ฟ ํ‚ค")); + } + + @DisplayName("ํ–‰์‚ฌ ์ฐธ์—ฌ ์ธ์›์˜ ์ด๋ฆ„์„ ์ˆ˜์ •ํ•œ๋‹ค.") + @Test + void updateMember() throws Exception { + String token = "TOKEN"; + MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( + new MemberNameUpdateRequest("ํ† ๋‹ค๋ง", "ํ† ์Ÿ์ด"), + new MemberNameUpdateRequest("๊ฐ์ž", "๊ณ ๊ตฌ๋งˆ") + )); + + String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + + mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("ํ–‰์‚ฌ ์–ด๋“œ๋ฏผ์ด ๋กœ๊ทธ์ธํ•œ๋‹ค.") + @Test + void loginEvent() throws Exception { + String token = "TOKEN"; + EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); + String requestBody = objectMapper.writeValueAsString(eventLoginRequest); + given(authService.createToken(token)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events/{eventId}/login", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java new file mode 100644 index 000000000..f50c70a17 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -0,0 +1,74 @@ +package server.haengdong.presentation; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +class MemberActionControllerTest extends ControllerTestSupport { + + @DisplayName("์ฐธ์—ฌ์ž ํ–‰๋™์„ ์ถ”๊ฐ€ํ•œ๋‹ค.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( + List.of("์›จ๋””", "์†Œํ•˜", "ํ† ๋‹ค๋ฆฌ", "์ฟ ํ‚ค"), "IN"); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/events/{eventId}/member-actions", "๋ง์ตธํ† ํฐ") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("ํ˜„์žฌ ์ฐธ์—ฌ ์ธ์›์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.") + @Test + void getCurrentMembers() throws Exception { + List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( + new CurrentMemberAppResponse("์†Œํ•˜"), new CurrentMemberAppResponse("ํ† ๋‹ค๋ฆฌ")); + + given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "๋ง์ตธํ† ํฐ") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames[0]").value(equalTo("์†Œํ•˜"))) + .andExpect(jsonPath("$.memberNames[1]").value(equalTo("ํ† ๋‹ค๋ฆฌ"))); + } + + @DisplayName("์ด๋ฒคํŠธ์— ์†ํ•œ ๋ฉค๋ฒ„ ์•ก์…˜์„ ์‚ญ์ œํ•˜๋ฉด ์ดํ›„์— ๊ธฐ๋ก๋œ ํ•ด๋‹น ์ฐธ์—ฌ์ž์˜ ๋ชจ๋“  ๋ฉค๋ฒ„ ์•ก์…˜์„ ์‚ญ์ œํ•œ๋‹ค.") + @Test + void deleteMemberAction() throws Exception { + String eventId = "๋ง์ตธํ† ํฐ"; + Long actionId = 2L; + + mockMvc.perform(delete("/api/events/{eventId}/member-actions/{actionId}", eventId, actionId)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("ํ–‰์‚ฌ์˜ ์ „์ฒด ์ฐธ์—ฌ์ž ์ค‘์—์„œ ํŠน์ • ์ฐธ์—ฌ์ž์˜ ๋งด๋ฒ„ ์•ก์…˜์„ ์ „๋ถ€ ์‚ญ์ œํ•œ๋‹ค.") + @Test + void deleteMember() throws Exception { + String eventId = "๋ง์ตธํ† ํฐ"; + String memberName = "ํ–‰๋™๋Œ€์žฅ"; + + mockMvc.perform(delete("/api/events/{eventId}/members/{memberName}", eventId, memberName)) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java new file mode 100644 index 000000000..051fcae0f --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java @@ -0,0 +1,63 @@ +package server.haengdong.presentation.response; + + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; + +class StepsResponseTest { + + @DisplayName("์ด์›ƒํ•œ ๊ฐ™์€ ํƒ€์ž…์˜ ์•ก์…˜๋“ค์„ ๊ทธ๋ฃนํ™” ํ•˜์—ฌ ์‘๋‹ต๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.") + @Test + void of() { + List<ActionAppResponse> actions = List.of( + new ActionAppResponse(1L, "๋ง์ตธ", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "๋ฐฑํ˜ธ", null, 2L, ActionType.IN), + new ActionAppResponse(3L, "๊ฐ์žํƒ•", 10_000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "์ธ์ƒ๋„ค์ปท", 10_000L, 4L, ActionType.BILL), + new ActionAppResponse(5L, "์†Œํ•˜", null, 5L, ActionType.IN), + new ActionAppResponse(6L, "์›จ๋””", null, 6L, ActionType.IN), + new ActionAppResponse(7L, "๋ง์ตธ", null, 7L, ActionType.OUT), + new ActionAppResponse(8L, "๋ฐฑํ˜ธ", null, 8L, ActionType.OUT), + new ActionAppResponse(9L, "๋…ธ๋ž˜๋ฐฉ", 20_000L, 9L, ActionType.BILL) + ); + + StepsResponse stepsResponse = StepsResponse.of(actions); + + StepsResponse expected = new StepsResponse( + List.of( + new StepResponse("0์ฐจ", "IN", List.of("๋ง์ตธ", "๋ฐฑํ˜ธ"), List.of( + new ActionResponse(1L, "๋ง์ตธ", null, 1L), + new ActionResponse(2L, "๋ฐฑํ˜ธ", null, 2L) + )), + new StepResponse("1์ฐจ", "BILL", List.of("๋ง์ตธ", "๋ฐฑํ˜ธ"), List.of( + new ActionResponse(3L, "๊ฐ์žํƒ•", 10_000L, 3L), + new ActionResponse(4L, "์ธ์ƒ๋„ค์ปท", 10_000L, 4L) + )), + new StepResponse("1์ฐจ", "IN", List.of("๋ง์ตธ", "๋ฐฑํ˜ธ", "์†Œํ•˜", "์›จ๋””"), List.of( + new ActionResponse(5L, "์†Œํ•˜", null, 5L), + new ActionResponse(6L, "์›จ๋””", null, 6L) + )), + new StepResponse("1์ฐจ", "OUT", List.of("์†Œํ•˜", "์›จ๋””"), List.of( + new ActionResponse(7L, "๋ง์ตธ", null, 7L), + new ActionResponse(8L, "๋ฐฑํ˜ธ", null, 8L) + )), + new StepResponse("2์ฐจ", "BILL", List.of("์†Œํ•˜", "์›จ๋””"), List.of( + new ActionResponse(9L, "๋…ธ๋ž˜๋ฐฉ", 20_000L, 9L) + )) + ) + ); + assertThat(stepsResponse).isEqualTo(expected); + } + + @DisplayName("์•ก์…˜์ด ์—†์œผ๋ฉด ๋นˆ ์Šคํƒญ๋“ค์ด ๋งŒ๋“ค์–ด์ง„๋‹ค.") + @Test + void ofEmpty() { + StepsResponse stepsResponse = StepsResponse.of(List.of()); + assertThat(stepsResponse.steps()).isEmpty(); + } +} diff --git a/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java b/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java new file mode 100644 index 000000000..346e81d2d --- /dev/null +++ b/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java @@ -0,0 +1,52 @@ +package server.haengdong.support.extension; + +import jakarta.annotation.PostConstruct; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import java.util.List; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +class DatabaseCleaner { + + private static final String REFERENTIAL_FORMAT = "set referential_integrity %b;"; + private static final String TRUNCATE_FORMAT = "truncate table %s restart identity;"; + + @PersistenceContext + private EntityManager em; + private String truncateTablesQuery; + + @PostConstruct + public void createTruncateQuery() { + List<String> tableNames = getTableNames(); + StringBuilder stringBuilder = new StringBuilder(); + + for (String tableName : tableNames) { + String truncateQuery = String.format(TRUNCATE_FORMAT, tableName); + stringBuilder.append(truncateQuery); + } + truncateTablesQuery = stringBuilder.toString(); + } + + private List<String> getTableNames() { + String sql = """ + select table_name + from information_schema.tables + where table_schema = 'PUBLIC' + """; + return em.createNativeQuery(sql).getResultList(); + } + + @Transactional + public void clear() { + em.clear(); + truncate(); + } + + private void truncate() { + em.createNativeQuery(String.format(REFERENTIAL_FORMAT, false)).executeUpdate(); + em.createNativeQuery(truncateTablesQuery).executeUpdate(); + em.createNativeQuery(String.format(REFERENTIAL_FORMAT, true)).executeUpdate(); + } +} diff --git a/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java b/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java new file mode 100644 index 000000000..653ecadb3 --- /dev/null +++ b/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java @@ -0,0 +1,19 @@ +package server.haengdong.support.extension; + +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +public class DatabaseCleanerExtension implements AfterEachCallback { + + @Override + public void afterEach(ExtensionContext context) { + DatabaseCleaner databaseCleaner = getDataCleaner(context); + databaseCleaner.clear(); + } + + private DatabaseCleaner getDataCleaner(ExtensionContext extensionContext) { + return SpringExtension.getApplicationContext(extensionContext) + .getBean(DatabaseCleaner.class); + } +} diff --git a/server/src/test/java/server/haengdong/support/fixture/Fixture.java b/server/src/test/java/server/haengdong/support/fixture/Fixture.java new file mode 100644 index 000000000..6844915d9 --- /dev/null +++ b/server/src/test/java/server/haengdong/support/fixture/Fixture.java @@ -0,0 +1,15 @@ +package server.haengdong.support.fixture; + +import jakarta.servlet.http.Cookie; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.event.Event; + +public class Fixture { + + public static final Event EVENT1 = new Event("์ฟ ํ‚ค", "1234", "TOKEN1"); + public static final Event EVENT2 = new Event("์›จ๋””", "1234", "TOKEN2"); + public static final Cookie EVENT_COOKIE = new Cookie("eventToken", "ํ† ํฐํ† ํฐ"); + public static final Action ACTION = new Action(EVENT1, 1L); + public static final BillAction BILL_ACTION = new BillAction(ACTION, "๋ฝ•์กฑ", 30_000L); +}